Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * Copyright (c) 2015 Hardware-Software-CoDesign, University of Erlangen-Nuremberg.
- *
- * This library is free software; you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option) any
- * later version.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
- * details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * --- This software and any associated documentation is provided "as is"
- *
- * IN NO EVENT SHALL HARDWARE-SOFTWARE-CODESIGN, UNIVERSITY OF ERLANGEN NUREMBERG
- * BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
- * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
- * DOCUMENTATION, EVEN IF HARDWARE-SOFTWARE-CODESIGN, UNIVERSITY OF ERLANGEN
- * NUREMBERG HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * HARDWARE-SOFTWARE-CODESIGN, UNIVERSITY OF ERLANGEN NUREMBERG, SPECIFICALLY
- * DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED
- * HEREUNDER IS ON AN "AS IS" BASIS, AND HARDWARE-SOFTWARE-CODESIGN, UNIVERSITY OF
- * ERLANGEN NUREMBERG HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
- * ENHANCEMENTS, OR MODIFICATIONS.
- */
- #include "calibrate.hpp"
- #include <string.h>
- #include <assert.h>
- #include <stdio.h>
- #include <iostream>
- #include <config.h>
- // Task 5h) Add the ctrl parameter of the appropriate Control structure type
- // to the dumpRegs function. This Control structure specifies the register
- // file that should be dumped. This Control structure is declared in the
- // header file pkginclude-sw/VideoFilterSkinColorDetectorWithCtrl.hpp contained
- // in the hwVideoFilterSkinColorDetectorWithCtrl project.
- void dumpRegs(VideoFilterSkinColorDetectorWithCtrl::Control& ctrl) {
- // Task 5n) Implement the dumpRegs functions to dump the fields of the
- // control structure that you are interested in for debugging purposes.
- // You can take notes from the implementation of the dumpRegs function
- // for the VideoSourceFromMem hardware module.
- printf("Calibrate Regs@0x%016lx: ",
- reinterpret_cast<unsigned long>(&ctrl));
- Register<00, 8, uint8_t, BIG_ENDIAN, 8> const *regs =
- reinterpret_cast<Register<00, 8, uint8_t, BIG_ENDIAN, 8> const *>(&ctrl);
- for (unsigned int i = 0; i < sizeof(ctrl); ++i) {
- printf("0x%02x%s", static_cast<int>(regs[i]),
- i == sizeof(ctrl)-1 ? "\n" : " ");
- }
- printf("CalibrateMode: %d, ColorSpace: %d \n",
- static_cast<int>(ctrl.calibrateMode.get()),
- static_cast<int>(ctrl.colorSpace.get())
- );
- for(int i = 0; i < 2; i++){
- if (ctrl.calibrateMode.get()) {
- printf("Region %d \n", i);
- printf("Position: x[%d], y[%d]\n"
- "Width[%d], Height[%d]\n",
- static_cast<int>(ctrl.calibrateSettings[i].boxStart.posx.get()),
- static_cast<int>(ctrl.calibrateSettings[i].boxStart.posy.get()),
- static_cast<int>(ctrl.calibrateSettings[i].boxDims.width.get()),
- static_cast<int>(ctrl.calibrateSettings[i].boxDims.height.get()));
- } else {
- switch (ctrl.colorSpace.get()) {
- case VideoFilterSkinColorDetectorWithCtrl::CS_RGB:
- printf("detectViaRGBSettings:\n"
- "r = (%d - %d)\n"
- "g = (%d - %d)\n"
- "b = (%d - %d)\n",
- static_cast<int>(ctrl.detectViaRGBSettings[i].low.r.get()),
- static_cast<int>(ctrl.detectViaRGBSettings[i].high.r.get()),
- static_cast<int>(ctrl.detectViaRGBSettings[i].low.g.get()),
- static_cast<int>(ctrl.detectViaRGBSettings[i].high.g.get()),
- static_cast<int>(ctrl.detectViaRGBSettings[i].low.b.get()),
- static_cast<int>(ctrl.detectViaRGBSettings[i].high.b.get()));
- break;
- case VideoFilterSkinColorDetectorWithCtrl::CS_YUV:
- printf("detectViaYUVSettings:\n"
- "y = (%d - %d)\n"
- "u = (%d - %d)\n"
- "v = (%d - %d)\n",
- static_cast<int>(ctrl.detectViaYUVSettings[i].low.y.get()),
- static_cast<int>(ctrl.detectViaYUVSettings[i].high.y.get()),
- static_cast<int>(ctrl.detectViaYUVSettings[i].low.u.get()),
- static_cast<int>(ctrl.detectViaYUVSettings[i].high.u.get()),
- static_cast<int>(ctrl.detectViaYUVSettings[i].low.v.get()),
- static_cast<int>(ctrl.detectViaYUVSettings[i].high.v.get()));
- break;
- case VideoFilterSkinColorDetectorWithCtrl::CS_HSY:
- printf("detectViaHSYSettings:\n"
- "h = (%d - %d)\n"
- "s = (%d - %d)\n"
- "y = (%d - %d)\n",
- static_cast<int>(ctrl.detectViaHSYSettings[i].low.h.get()),
- static_cast<int>(ctrl.detectViaHSYSettings[i].high.h.get()),
- static_cast<int>(ctrl.detectViaHSYSettings[i].low.s.get()),
- static_cast<int>(ctrl.detectViaHSYSettings[i].high.s.get()),
- static_cast<int>(ctrl.detectViaHSYSettings[i].low.y.get()),
- static_cast<int>(ctrl.detectViaHSYSettings[i].high.y.get()));
- }
- }
- }
- }
- namespace {
- struct CalibrateRegion {
- unsigned char *fb;
- unsigned int imageWidth;
- unsigned int posx, posy;
- unsigned int width, height;
- };
- struct ChannelRange
- : public std::pair<int, int>
- {
- ChannelRange(unsigned char first = 0, unsigned char second = 0)
- : std::pair<int, int>(first, second) {}
- ChannelRange &widen(unsigned char n, bool wrap = false) {
- if (!wrap) {
- if (first >= n)
- first -= n;
- if (second <= 255-n)
- second += n;
- } else if (first <= second) {
- if (256 - (second-first+1) <= 2*n) {
- first = 0;
- second = 255;
- } else {
- first = static_cast<unsigned char>(first-n);
- second = static_cast<unsigned char>(second+n);
- }
- } else {
- if (first-second-1 <= 2*n) {
- first = 0;
- second = 255;
- } else {
- first = static_cast<unsigned char>(first-n);
- second = static_cast<unsigned char>(second+n);
- }
- }
- return *this;
- }
- };
- class Histogram {
- public:
- Histogram();
- void countPixelColors(CalibrateRegion const &cr);
- ChannelRange getSpanRGB_R() const
- { return getSpan(histoRed).widen(16); }
- ChannelRange getSpanRGB_G() const
- { return getSpan(histoGreen).widen(16); }
- ChannelRange getSpanRGB_B() const
- { return getSpan(histoBlue).widen(16); }
- ChannelRange getSpanYUV_Y() const
- { return getSpan(histoRed).widen(16); }
- ChannelRange getSpanYUV_U() const
- { return getSpan(histoGreen).widen(16); }
- ChannelRange getSpanYUV_V() const
- { return getSpan(histoBlue).widen(16); }
- ChannelRange getSpanHSY_H() const
- { return getSpan(histoRed, true).widen(16, true); }
- ChannelRange getSpanHSY_S() const
- { return getSpan(histoGreen).widen(16); }
- ChannelRange getSpanHSY_Y() const
- { return getSpan(histoBlue).widen(16); }
- private:
- unsigned int allPixelsInBox;
- unsigned int histoRed [256];
- unsigned int histoGreen [256];
- unsigned int histoBlue [256];
- ChannelRange getSpan(unsigned int const histo[256], bool wrap = false) const;
- };
- Histogram::Histogram() {
- allPixelsInBox = 0;
- memset(histoRed, 0, sizeof(histoRed));
- memset(histoGreen, 0, sizeof(histoGreen));
- memset(histoBlue, 0, sizeof(histoBlue));
- }
- void Histogram::countPixelColors(CalibrateRegion const &cr) {
- // This code performs the histogram calculation, you may switch to
- // YUV or HSY color space based histograms for better performance
- // under different lighting conditions!
- // take all pixels from calibrate region and calculate histogram
- allPixelsInBox += (cr.width-2)*(cr.height-2);
- for (unsigned int k = cr.posy+1; k < cr.posy + cr.height-1; k++) {
- for (unsigned int l = cr.posx+1; l < cr.posx + cr.width-1; l++) {
- unsigned char *pixelAddress = cr.fb + (cr.imageWidth * k + l) * 3;
- histoRed [pixelAddress[0]]++;
- histoGreen[pixelAddress[1]]++;
- histoBlue [pixelAddress[2]]++;
- }
- }
- }
- ChannelRange Histogram::getSpan(unsigned int const histo[256], bool wrap) const {
- unsigned int histoSum[257];
- histoSum[0] = 0;
- for(int i = 1; i < 257; i++)
- histoSum[i] = histoSum[i-1] + histo[i-1];
- assert(histoSum[256] == allPixelsInBox);
- unsigned int threshold = 0.975 * allPixelsInBox;
- for(int span = 1; span <= 256; span++) {
- for(int lowBound = 0; lowBound <= 256-span; lowBound++) {
- if (histoSum[span+lowBound] - histoSum[lowBound] > threshold)
- return ChannelRange(lowBound, lowBound+span-1);
- }
- }
- assert(!"Oops, this should never happen!");
- }
- } // anonymous namespace
- // Task 5i) Add the parameters colorSpace, ctrlSKCD, and ctrlVS2MEM of the
- // appropriate control structure types to the calibrate function.
- void calibrate(VideoFilterSkinColorDetectorWithCtrl::ColorSpace colorSpace,
- VideoFilterSkinColorDetectorWithCtrl::Control &ctrlSKCD,
- VideoSinkToMem::Control &ctrlVS2MEM) {
- // Task 5o) In the calibrate function, switch on calibrate mode in register
- // file ctrlSKCD. Then, use ctrlSKCD.calibrateSettings[0] to display a
- // calibrate box of dimensions 10% of the input image width and height with
- // the lower right corner at 40% width and 25% height of the input image.
- // If you need a second color, use ctrlSKCD.calibrateSettings[1] to display
- // a calibrate box of the same dimensions but with the upper left corner at
- // 60 % width and 75 % height of the input image.
- ctrlSKCD.calibrateMode.set(1);
- CalibrateRegion cr0, cr1;
- //top left square
- cr0.fb = ctrlVS2MEM.buf.addr.get();
- cr0.imageWidth = ctrlVS2MEM.dim.width.get();
- cr0.width = 0.1f * ctrlVS2MEM.dim.width.get();
- ctrlSKCD.calibrateSettings[0].boxDims.width.set(cr0.width);
- cr0.height = 0.1f * ctrlVS2MEM.dim.height.get();
- ctrlSKCD.calibrateSettings[0].boxDims.height.set(cr0.height);
- cr0.posx = 0.4f * ctrlVS2MEM.dim.width.get();
- ctrlSKCD.calibrateSettings[0].boxStart.posx.set(cr0.posx);
- cr0.posy = 0.25f * ctrlVS2MEM.dim.height.get();
- ctrlSKCD.calibrateSettings[0].boxStart.posy.set(cr0.posy);
- //bottom right square
- cr1.fb = ctrlVS2MEM.buf.addr.get();
- cr1.imageWidth = ctrlVS2MEM.dim.width.get();
- cr1.width = 0.1f * ctrlVS2MEM.dim.width.get();
- ctrlSKCD.calibrateSettings[1].boxDims.width.set(cr1.width);
- cr1.height = 0.1f * ctrlVS2MEM.dim.height.get();
- ctrlSKCD.calibrateSettings[1].boxDims.height.set(cr1.height);
- cr1.posx = 0.6f * ctrlVS2MEM.dim.width.get();
- ctrlSKCD.calibrateSettings[1].boxStart.posx.set(cr1.posx);
- cr1.posy = 0.75f * ctrlVS2MEM.dim.height.get();
- ctrlSKCD.calibrateSettings[1].boxStart.posy.set(cr1.posy);
- dumpRegs(ctrlSKCD);
- // Task 5p) However, you should not immediately start with histogram calibration
- // in order to give the user time to move the desired colors into the calibrate
- // regions. Here, it is useful to slightly move the position of the calibration
- // boxes during the waiting time to give feedback to the user that calibration
- // has not yet begun. Select an appropriate waiting time an slightly shake the
- // position of the calibration boxes during this time.
- int imageCount = 0;
- bool direction = false;
- for(int i = 0; i < 2; i++){
- //wait for 20 images
- while(ctrlVS2MEM.dim.count == imageCount){
- //wait for new image and move region left or right to create wiggle effect
- int wiggleFactor = 3;
- if(direction){
- cr0.posx += wiggleFactor;
- ctrlSKCD.calibrateSettings[0].boxStart.posx.set(cr0.posx);
- cr1.posx += wiggleFactor;
- ctrlSKCD.calibrateSettings[1].boxStart.posx.set(cr1.posx);
- }else{
- cr0.posx -= wiggleFactor;
- ctrlSKCD.calibrateSettings[0].boxStart.posx.set(cr0.posx);
- cr1.posx -= wiggleFactor;
- ctrlSKCD.calibrateSettings[1].boxStart.posx.set(cr1.posx);
- }
- direction = !direction;
- }
- imageCount = ctrlVS2MEM.dim.count;
- }
- dumpRegs(ctrlSKCD);
- // Task 5q) Call countPixelColors for each calibration region with
- // five different input images.
- Histogram h0, h1;
- for(int i = 0; i < 5; i++){
- //process 5 images
- while(ctrlVS2MEM.dim.count == imageCount){
- //wait for new image
- }
- std::cout << "count" << std::endl;
- h0.countPixelColors(cr0);
- h1.countPixelColors(cr1);
- imageCount = ctrlVS2MEM.dim.count;
- }
- // Task 5r) Enable skin color detection with the histogram bounds the
- // getSpanRGB_{R,G,B} methods have determined.
- if(colorSpace == VideoFilterSkinColorDetectorWithCtrl::ColorSpace::CS_RGB){
- ChannelRange r[2] = {h0.getSpanRGB_R(), h1.getSpanRGB_R()};
- ChannelRange g[2] = {h0.getSpanRGB_G(), h1.getSpanRGB_G()};
- ChannelRange b[2] = {h0.getSpanRGB_B(), h1.getSpanRGB_B()};
- ctrlSKCD.detectViaRGBSettings[0].low.r.set((uint8_t)r[0].first);
- ctrlSKCD.detectViaRGBSettings[0].low.g.set((uint8_t)g[0].first);
- ctrlSKCD.detectViaRGBSettings[0].low.b.set((uint8_t)b[0].first);
- ctrlSKCD.detectViaRGBSettings[0].high.r.set((uint8_t)r[0].second);
- ctrlSKCD.detectViaRGBSettings[0].high.g.set((uint8_t)g[0].second);
- ctrlSKCD.detectViaRGBSettings[0].high.b.set((uint8_t)b[0].second);
- ctrlSKCD.detectViaRGBSettings[1].low.r.set((uint8_t)r[1].first);
- ctrlSKCD.detectViaRGBSettings[1].low.g.set((uint8_t)g[1].first);
- ctrlSKCD.detectViaRGBSettings[1].low.b.set((uint8_t)b[1].first);
- ctrlSKCD.detectViaRGBSettings[1].high.r.set((uint8_t)r[1].second);
- ctrlSKCD.detectViaRGBSettings[1].high.g.set((uint8_t)g[1].second);
- ctrlSKCD.detectViaRGBSettings[1].high.b.set((uint8_t)b[1].second);
- }
- if(colorSpace == VideoFilterSkinColorDetectorWithCtrl::ColorSpace::CS_YUV){
- ChannelRange y[2] = {h0.getSpanYUV_Y(), h1.getSpanYUV_Y()};
- ChannelRange u[2] = {h0.getSpanYUV_U(), h1.getSpanYUV_U()};
- ChannelRange v[2] = {h0.getSpanYUV_V(), h1.getSpanYUV_V()};
- ctrlSKCD.detectViaYUVSettings[0].low.y.set(y[0].first);
- ctrlSKCD.detectViaYUVSettings[0].low.u.set(u[0].first);
- ctrlSKCD.detectViaYUVSettings[0].low.v.set(v[0].first);
- ctrlSKCD.detectViaYUVSettings[0].high.y.set(y[0].second);
- ctrlSKCD.detectViaYUVSettings[0].high.u.set(u[0].second);
- ctrlSKCD.detectViaYUVSettings[0].high.v.set(v[0].second);
- ctrlSKCD.detectViaYUVSettings[1].low.y.set(y[1].first);
- ctrlSKCD.detectViaYUVSettings[1].low.u.set(u[1].first);
- ctrlSKCD.detectViaYUVSettings[1].low.v.set(v[1].first);
- ctrlSKCD.detectViaYUVSettings[1].high.y.set(y[1].second);
- ctrlSKCD.detectViaYUVSettings[1].high.u.set(u[1].second);
- ctrlSKCD.detectViaYUVSettings[1].high.v.set(v[1].second);
- }
- if(colorSpace == VideoFilterSkinColorDetectorWithCtrl::ColorSpace::CS_HSY){
- ChannelRange h[2] = {h0.getSpanHSY_H(), h1.getSpanHSY_H()};
- ChannelRange s[2] = {h0.getSpanHSY_S(), h1.getSpanHSY_S()};
- ChannelRange y[2] = {h0.getSpanHSY_Y(), h1.getSpanHSY_Y()};
- ctrlSKCD.detectViaHSYSettings[0].low.h.set(h[0].first);
- ctrlSKCD.detectViaHSYSettings[0].low.s.set(s[0].first);
- ctrlSKCD.detectViaHSYSettings[0].low.y.set(y[0].first);
- ctrlSKCD.detectViaHSYSettings[0].high.h.set(h[0].second);
- ctrlSKCD.detectViaHSYSettings[0].high.s.set(s[0].second);
- ctrlSKCD.detectViaHSYSettings[0].high.y.set(y[0].second);
- ctrlSKCD.detectViaHSYSettings[1].low.h.set(h[1].first);
- ctrlSKCD.detectViaHSYSettings[1].low.s.set(s[1].first);
- ctrlSKCD.detectViaHSYSettings[1].low.y.set(y[1].first);
- ctrlSKCD.detectViaHSYSettings[1].high.h.set(h[1].second);
- ctrlSKCD.detectViaHSYSettings[1].high.s.set(s[1].second);
- ctrlSKCD.detectViaHSYSettings[1].high.y.set(y[1].second);
- }
- std::cout << "finished calibration" << std::endl;
- dumpRegs(ctrlSKCD);
- ctrlSKCD.calibrateMode.set(0);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement