Advertisement
Guest User

Untitled

a guest
Feb 22nd, 2018
50
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.58 KB | None | 0 0
  1. /*
  2. * Copyright (c) 2015 Hardware-Software-CoDesign, University of Erlangen-Nuremberg.
  3. *
  4. * This library is free software; you can redistribute it and/or modify it under
  5. * the terms of the GNU Lesser General Public License as published by the Free
  6. * Software Foundation; either version 2 of the License, or (at your option) any
  7. * later version.
  8. *
  9. * This library is distributed in the hope that it will be useful, but WITHOUT
  10. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  11. * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  12. * details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public License
  15. * along with this library; if not, write to the Free Software Foundation, Inc.,
  16. * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  17. *
  18. * --- This software and any associated documentation is provided "as is"
  19. *
  20. * IN NO EVENT SHALL HARDWARE-SOFTWARE-CODESIGN, UNIVERSITY OF ERLANGEN NUREMBERG
  21. * BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
  22. * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
  23. * DOCUMENTATION, EVEN IF HARDWARE-SOFTWARE-CODESIGN, UNIVERSITY OF ERLANGEN
  24. * NUREMBERG HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. *
  26. * HARDWARE-SOFTWARE-CODESIGN, UNIVERSITY OF ERLANGEN NUREMBERG, SPECIFICALLY
  27. * DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  28. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED
  29. * HEREUNDER IS ON AN "AS IS" BASIS, AND HARDWARE-SOFTWARE-CODESIGN, UNIVERSITY OF
  30. * ERLANGEN NUREMBERG HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
  31. * ENHANCEMENTS, OR MODIFICATIONS.
  32. */
  33.  
  34. #include "calibrate.hpp"
  35.  
  36. #include <string.h>
  37. #include <assert.h>
  38. #include <stdio.h>
  39.  
  40. #include <iostream>
  41.  
  42. #include <config.h>
  43.  
  44. // Task 5h) Add the ctrl parameter of the appropriate Control structure type
  45. // to the dumpRegs function. This Control structure specifies the register
  46. // file that should be dumped. This Control structure is declared in the
  47. // header file pkginclude-sw/VideoFilterSkinColorDetectorWithCtrl.hpp contained
  48. // in the hwVideoFilterSkinColorDetectorWithCtrl project.
  49. void dumpRegs(VideoFilterSkinColorDetectorWithCtrl::Control& ctrl) {
  50. // Task 5n) Implement the dumpRegs functions to dump the fields of the
  51. // control structure that you are interested in for debugging purposes.
  52. // You can take notes from the implementation of the dumpRegs function
  53. // for the VideoSourceFromMem hardware module.
  54. printf("Calibrate Regs@0x%016lx: ",
  55. reinterpret_cast<unsigned long>(&ctrl));
  56. Register<00, 8, uint8_t, BIG_ENDIAN, 8> const *regs =
  57. reinterpret_cast<Register<00, 8, uint8_t, BIG_ENDIAN, 8> const *>(&ctrl);
  58. for (unsigned int i = 0; i < sizeof(ctrl); ++i) {
  59. printf("0x%02x%s", static_cast<int>(regs[i]),
  60. i == sizeof(ctrl)-1 ? "\n" : " ");
  61. }
  62. printf("CalibrateMode: %d, ColorSpace: %d \n",
  63. static_cast<int>(ctrl.calibrateMode.get()),
  64. static_cast<int>(ctrl.colorSpace.get())
  65. );
  66. for(int i = 0; i < 2; i++){
  67. if (ctrl.calibrateMode.get()) {
  68. printf("Region %d \n", i);
  69. printf("Position: x[%d], y[%d]\n"
  70. "Width[%d], Height[%d]\n",
  71. static_cast<int>(ctrl.calibrateSettings[i].boxStart.posx.get()),
  72. static_cast<int>(ctrl.calibrateSettings[i].boxStart.posy.get()),
  73. static_cast<int>(ctrl.calibrateSettings[i].boxDims.width.get()),
  74. static_cast<int>(ctrl.calibrateSettings[i].boxDims.height.get()));
  75. } else {
  76. switch (ctrl.colorSpace.get()) {
  77. case VideoFilterSkinColorDetectorWithCtrl::CS_RGB:
  78. printf("detectViaRGBSettings:\n"
  79. "r = (%d - %d)\n"
  80. "g = (%d - %d)\n"
  81. "b = (%d - %d)\n",
  82. static_cast<int>(ctrl.detectViaRGBSettings[i].low.r.get()),
  83. static_cast<int>(ctrl.detectViaRGBSettings[i].high.r.get()),
  84. static_cast<int>(ctrl.detectViaRGBSettings[i].low.g.get()),
  85. static_cast<int>(ctrl.detectViaRGBSettings[i].high.g.get()),
  86. static_cast<int>(ctrl.detectViaRGBSettings[i].low.b.get()),
  87. static_cast<int>(ctrl.detectViaRGBSettings[i].high.b.get()));
  88. break;
  89. case VideoFilterSkinColorDetectorWithCtrl::CS_YUV:
  90. printf("detectViaYUVSettings:\n"
  91. "y = (%d - %d)\n"
  92. "u = (%d - %d)\n"
  93. "v = (%d - %d)\n",
  94. static_cast<int>(ctrl.detectViaYUVSettings[i].low.y.get()),
  95. static_cast<int>(ctrl.detectViaYUVSettings[i].high.y.get()),
  96. static_cast<int>(ctrl.detectViaYUVSettings[i].low.u.get()),
  97. static_cast<int>(ctrl.detectViaYUVSettings[i].high.u.get()),
  98. static_cast<int>(ctrl.detectViaYUVSettings[i].low.v.get()),
  99. static_cast<int>(ctrl.detectViaYUVSettings[i].high.v.get()));
  100. break;
  101. case VideoFilterSkinColorDetectorWithCtrl::CS_HSY:
  102. printf("detectViaHSYSettings:\n"
  103. "h = (%d - %d)\n"
  104. "s = (%d - %d)\n"
  105. "y = (%d - %d)\n",
  106. static_cast<int>(ctrl.detectViaHSYSettings[i].low.h.get()),
  107. static_cast<int>(ctrl.detectViaHSYSettings[i].high.h.get()),
  108. static_cast<int>(ctrl.detectViaHSYSettings[i].low.s.get()),
  109. static_cast<int>(ctrl.detectViaHSYSettings[i].high.s.get()),
  110. static_cast<int>(ctrl.detectViaHSYSettings[i].low.y.get()),
  111. static_cast<int>(ctrl.detectViaHSYSettings[i].high.y.get()));
  112. }
  113. }
  114. }
  115. }
  116.  
  117. namespace {
  118.  
  119. struct CalibrateRegion {
  120. unsigned char *fb;
  121. unsigned int imageWidth;
  122. unsigned int posx, posy;
  123. unsigned int width, height;
  124. };
  125.  
  126. struct ChannelRange
  127. : public std::pair<int, int>
  128. {
  129. ChannelRange(unsigned char first = 0, unsigned char second = 0)
  130. : std::pair<int, int>(first, second) {}
  131.  
  132. ChannelRange &widen(unsigned char n, bool wrap = false) {
  133. if (!wrap) {
  134. if (first >= n)
  135. first -= n;
  136. if (second <= 255-n)
  137. second += n;
  138. } else if (first <= second) {
  139. if (256 - (second-first+1) <= 2*n) {
  140. first = 0;
  141. second = 255;
  142. } else {
  143. first = static_cast<unsigned char>(first-n);
  144. second = static_cast<unsigned char>(second+n);
  145. }
  146. } else {
  147. if (first-second-1 <= 2*n) {
  148. first = 0;
  149. second = 255;
  150. } else {
  151. first = static_cast<unsigned char>(first-n);
  152. second = static_cast<unsigned char>(second+n);
  153. }
  154. }
  155. return *this;
  156. }
  157. };
  158.  
  159. class Histogram {
  160. public:
  161. Histogram();
  162.  
  163. void countPixelColors(CalibrateRegion const &cr);
  164.  
  165. ChannelRange getSpanRGB_R() const
  166. { return getSpan(histoRed).widen(16); }
  167. ChannelRange getSpanRGB_G() const
  168. { return getSpan(histoGreen).widen(16); }
  169. ChannelRange getSpanRGB_B() const
  170. { return getSpan(histoBlue).widen(16); }
  171. ChannelRange getSpanYUV_Y() const
  172. { return getSpan(histoRed).widen(16); }
  173. ChannelRange getSpanYUV_U() const
  174. { return getSpan(histoGreen).widen(16); }
  175. ChannelRange getSpanYUV_V() const
  176. { return getSpan(histoBlue).widen(16); }
  177. ChannelRange getSpanHSY_H() const
  178. { return getSpan(histoRed, true).widen(16, true); }
  179. ChannelRange getSpanHSY_S() const
  180. { return getSpan(histoGreen).widen(16); }
  181. ChannelRange getSpanHSY_Y() const
  182. { return getSpan(histoBlue).widen(16); }
  183. private:
  184. unsigned int allPixelsInBox;
  185. unsigned int histoRed [256];
  186. unsigned int histoGreen [256];
  187. unsigned int histoBlue [256];
  188.  
  189. ChannelRange getSpan(unsigned int const histo[256], bool wrap = false) const;
  190. };
  191.  
  192. Histogram::Histogram() {
  193. allPixelsInBox = 0;
  194. memset(histoRed, 0, sizeof(histoRed));
  195. memset(histoGreen, 0, sizeof(histoGreen));
  196. memset(histoBlue, 0, sizeof(histoBlue));
  197. }
  198.  
  199. void Histogram::countPixelColors(CalibrateRegion const &cr) {
  200. // This code performs the histogram calculation, you may switch to
  201. // YUV or HSY color space based histograms for better performance
  202. // under different lighting conditions!
  203.  
  204. // take all pixels from calibrate region and calculate histogram
  205. allPixelsInBox += (cr.width-2)*(cr.height-2);
  206. for (unsigned int k = cr.posy+1; k < cr.posy + cr.height-1; k++) {
  207. for (unsigned int l = cr.posx+1; l < cr.posx + cr.width-1; l++) {
  208. unsigned char *pixelAddress = cr.fb + (cr.imageWidth * k + l) * 3;
  209. histoRed [pixelAddress[0]]++;
  210. histoGreen[pixelAddress[1]]++;
  211. histoBlue [pixelAddress[2]]++;
  212. }
  213. }
  214. }
  215.  
  216. ChannelRange Histogram::getSpan(unsigned int const histo[256], bool wrap) const {
  217. unsigned int histoSum[257];
  218. histoSum[0] = 0;
  219. for(int i = 1; i < 257; i++)
  220. histoSum[i] = histoSum[i-1] + histo[i-1];
  221.  
  222. assert(histoSum[256] == allPixelsInBox);
  223. unsigned int threshold = 0.975 * allPixelsInBox;
  224.  
  225. for(int span = 1; span <= 256; span++) {
  226. for(int lowBound = 0; lowBound <= 256-span; lowBound++) {
  227. if (histoSum[span+lowBound] - histoSum[lowBound] > threshold)
  228. return ChannelRange(lowBound, lowBound+span-1);
  229. }
  230. }
  231. assert(!"Oops, this should never happen!");
  232. }
  233.  
  234. } // anonymous namespace
  235.  
  236. // Task 5i) Add the parameters colorSpace, ctrlSKCD, and ctrlVS2MEM of the
  237. // appropriate control structure types to the calibrate function.
  238. void calibrate(VideoFilterSkinColorDetectorWithCtrl::ColorSpace colorSpace,
  239. VideoFilterSkinColorDetectorWithCtrl::Control &ctrlSKCD,
  240. VideoSinkToMem::Control &ctrlVS2MEM) {
  241.  
  242. // Task 5o) In the calibrate function, switch on calibrate mode in register
  243. // file ctrlSKCD. Then, use ctrlSKCD.calibrateSettings[0] to display a
  244. // calibrate box of dimensions 10% of the input image width and height with
  245. // the lower right corner at 40% width and 25% height of the input image.
  246. // If you need a second color, use ctrlSKCD.calibrateSettings[1] to display
  247. // a calibrate box of the same dimensions but with the upper left corner at
  248. // 60 % width and 75 % height of the input image.
  249. ctrlSKCD.calibrateMode.set(1);
  250.  
  251. CalibrateRegion cr0, cr1;
  252.  
  253. //top left square
  254. cr0.fb = ctrlVS2MEM.buf.addr.get();
  255. cr0.imageWidth = ctrlVS2MEM.dim.width.get();
  256.  
  257. cr0.width = 0.1f * ctrlVS2MEM.dim.width.get();
  258. ctrlSKCD.calibrateSettings[0].boxDims.width.set(cr0.width);
  259. cr0.height = 0.1f * ctrlVS2MEM.dim.height.get();
  260. ctrlSKCD.calibrateSettings[0].boxDims.height.set(cr0.height);
  261. cr0.posx = 0.4f * ctrlVS2MEM.dim.width.get();
  262. ctrlSKCD.calibrateSettings[0].boxStart.posx.set(cr0.posx);
  263. cr0.posy = 0.25f * ctrlVS2MEM.dim.height.get();
  264. ctrlSKCD.calibrateSettings[0].boxStart.posy.set(cr0.posy);
  265.  
  266. //bottom right square
  267. cr1.fb = ctrlVS2MEM.buf.addr.get();
  268. cr1.imageWidth = ctrlVS2MEM.dim.width.get();
  269.  
  270. cr1.width = 0.1f * ctrlVS2MEM.dim.width.get();
  271. ctrlSKCD.calibrateSettings[1].boxDims.width.set(cr1.width);
  272. cr1.height = 0.1f * ctrlVS2MEM.dim.height.get();
  273. ctrlSKCD.calibrateSettings[1].boxDims.height.set(cr1.height);
  274. cr1.posx = 0.6f * ctrlVS2MEM.dim.width.get();
  275. ctrlSKCD.calibrateSettings[1].boxStart.posx.set(cr1.posx);
  276. cr1.posy = 0.75f * ctrlVS2MEM.dim.height.get();
  277. ctrlSKCD.calibrateSettings[1].boxStart.posy.set(cr1.posy);
  278.  
  279. dumpRegs(ctrlSKCD);
  280.  
  281. // Task 5p) However, you should not immediately start with histogram calibration
  282. // in order to give the user time to move the desired colors into the calibrate
  283. // regions. Here, it is useful to slightly move the position of the calibration
  284. // boxes during the waiting time to give feedback to the user that calibration
  285. // has not yet begun. Select an appropriate waiting time an slightly shake the
  286. // position of the calibration boxes during this time.
  287.  
  288. int imageCount = 0;
  289. bool direction = false;
  290.  
  291. for(int i = 0; i < 2; i++){
  292. //wait for 20 images
  293. while(ctrlVS2MEM.dim.count == imageCount){
  294. //wait for new image and move region left or right to create wiggle effect
  295. int wiggleFactor = 3;
  296. if(direction){
  297. cr0.posx += wiggleFactor;
  298. ctrlSKCD.calibrateSettings[0].boxStart.posx.set(cr0.posx);
  299. cr1.posx += wiggleFactor;
  300. ctrlSKCD.calibrateSettings[1].boxStart.posx.set(cr1.posx);
  301. }else{
  302. cr0.posx -= wiggleFactor;
  303. ctrlSKCD.calibrateSettings[0].boxStart.posx.set(cr0.posx);
  304. cr1.posx -= wiggleFactor;
  305. ctrlSKCD.calibrateSettings[1].boxStart.posx.set(cr1.posx);
  306. }
  307. direction = !direction;
  308. }
  309. imageCount = ctrlVS2MEM.dim.count;
  310. }
  311. dumpRegs(ctrlSKCD);
  312. // Task 5q) Call countPixelColors for each calibration region with
  313. // five different input images.
  314.  
  315. Histogram h0, h1;
  316.  
  317. for(int i = 0; i < 5; i++){
  318. //process 5 images
  319. while(ctrlVS2MEM.dim.count == imageCount){
  320. //wait for new image
  321. }
  322. std::cout << "count" << std::endl;
  323. h0.countPixelColors(cr0);
  324. h1.countPixelColors(cr1);
  325. imageCount = ctrlVS2MEM.dim.count;
  326. }
  327.  
  328. // Task 5r) Enable skin color detection with the histogram bounds the
  329. // getSpanRGB_{R,G,B} methods have determined.
  330. if(colorSpace == VideoFilterSkinColorDetectorWithCtrl::ColorSpace::CS_RGB){
  331.  
  332. ChannelRange r[2] = {h0.getSpanRGB_R(), h1.getSpanRGB_R()};
  333. ChannelRange g[2] = {h0.getSpanRGB_G(), h1.getSpanRGB_G()};
  334. ChannelRange b[2] = {h0.getSpanRGB_B(), h1.getSpanRGB_B()};
  335.  
  336. ctrlSKCD.detectViaRGBSettings[0].low.r.set((uint8_t)r[0].first);
  337. ctrlSKCD.detectViaRGBSettings[0].low.g.set((uint8_t)g[0].first);
  338. ctrlSKCD.detectViaRGBSettings[0].low.b.set((uint8_t)b[0].first);
  339. ctrlSKCD.detectViaRGBSettings[0].high.r.set((uint8_t)r[0].second);
  340. ctrlSKCD.detectViaRGBSettings[0].high.g.set((uint8_t)g[0].second);
  341. ctrlSKCD.detectViaRGBSettings[0].high.b.set((uint8_t)b[0].second);
  342.  
  343. ctrlSKCD.detectViaRGBSettings[1].low.r.set((uint8_t)r[1].first);
  344. ctrlSKCD.detectViaRGBSettings[1].low.g.set((uint8_t)g[1].first);
  345. ctrlSKCD.detectViaRGBSettings[1].low.b.set((uint8_t)b[1].first);
  346. ctrlSKCD.detectViaRGBSettings[1].high.r.set((uint8_t)r[1].second);
  347. ctrlSKCD.detectViaRGBSettings[1].high.g.set((uint8_t)g[1].second);
  348. ctrlSKCD.detectViaRGBSettings[1].high.b.set((uint8_t)b[1].second);
  349. }
  350. if(colorSpace == VideoFilterSkinColorDetectorWithCtrl::ColorSpace::CS_YUV){
  351.  
  352. ChannelRange y[2] = {h0.getSpanYUV_Y(), h1.getSpanYUV_Y()};
  353. ChannelRange u[2] = {h0.getSpanYUV_U(), h1.getSpanYUV_U()};
  354. ChannelRange v[2] = {h0.getSpanYUV_V(), h1.getSpanYUV_V()};
  355.  
  356. ctrlSKCD.detectViaYUVSettings[0].low.y.set(y[0].first);
  357. ctrlSKCD.detectViaYUVSettings[0].low.u.set(u[0].first);
  358. ctrlSKCD.detectViaYUVSettings[0].low.v.set(v[0].first);
  359. ctrlSKCD.detectViaYUVSettings[0].high.y.set(y[0].second);
  360. ctrlSKCD.detectViaYUVSettings[0].high.u.set(u[0].second);
  361. ctrlSKCD.detectViaYUVSettings[0].high.v.set(v[0].second);
  362.  
  363. ctrlSKCD.detectViaYUVSettings[1].low.y.set(y[1].first);
  364. ctrlSKCD.detectViaYUVSettings[1].low.u.set(u[1].first);
  365. ctrlSKCD.detectViaYUVSettings[1].low.v.set(v[1].first);
  366. ctrlSKCD.detectViaYUVSettings[1].high.y.set(y[1].second);
  367. ctrlSKCD.detectViaYUVSettings[1].high.u.set(u[1].second);
  368. ctrlSKCD.detectViaYUVSettings[1].high.v.set(v[1].second);
  369. }
  370. if(colorSpace == VideoFilterSkinColorDetectorWithCtrl::ColorSpace::CS_HSY){
  371.  
  372. ChannelRange h[2] = {h0.getSpanHSY_H(), h1.getSpanHSY_H()};
  373. ChannelRange s[2] = {h0.getSpanHSY_S(), h1.getSpanHSY_S()};
  374. ChannelRange y[2] = {h0.getSpanHSY_Y(), h1.getSpanHSY_Y()};
  375.  
  376. ctrlSKCD.detectViaHSYSettings[0].low.h.set(h[0].first);
  377. ctrlSKCD.detectViaHSYSettings[0].low.s.set(s[0].first);
  378. ctrlSKCD.detectViaHSYSettings[0].low.y.set(y[0].first);
  379. ctrlSKCD.detectViaHSYSettings[0].high.h.set(h[0].second);
  380. ctrlSKCD.detectViaHSYSettings[0].high.s.set(s[0].second);
  381. ctrlSKCD.detectViaHSYSettings[0].high.y.set(y[0].second);
  382.  
  383. ctrlSKCD.detectViaHSYSettings[1].low.h.set(h[1].first);
  384. ctrlSKCD.detectViaHSYSettings[1].low.s.set(s[1].first);
  385. ctrlSKCD.detectViaHSYSettings[1].low.y.set(y[1].first);
  386. ctrlSKCD.detectViaHSYSettings[1].high.h.set(h[1].second);
  387. ctrlSKCD.detectViaHSYSettings[1].high.s.set(s[1].second);
  388. ctrlSKCD.detectViaHSYSettings[1].high.y.set(y[1].second);
  389. }
  390. std::cout << "finished calibration" << std::endl;
  391. dumpRegs(ctrlSKCD);
  392. ctrlSKCD.calibrateMode.set(0);
  393. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement