fork download
  1. #include <cv.h>
  2. #include <highgui.h>
  3. #include <math.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6.  
  7. void cv_adjustBox(int x, int y, CvPoint& A, CvPoint& B);
  8.  
  9. int main()
  10. {
  11. IplImage* img = 0;
  12. img = cvLoadImage("cardtest.png",1);
  13. IplImage* gray = 0;
  14. IplImage* thres = 0;
  15. IplImage* prcs_flg = 0;
  16. int q,i; // Intermidiate variables
  17. int h,w; // Variables to store Image Height and Width
  18.  
  19. int ihist[256]; // Array to store Histogram values
  20. float hist_val[256]; // Array to store Normalised Histogram values
  21.  
  22. int blob_count;
  23. int n; // Number of pixels in a blob
  24. int pos ; // Position or pixel value of the image
  25.  
  26. int rectw,recth; // Width and Height of the Bounding Box
  27. double aspect_ratio; // Aspect Ratio of the Bounding Box
  28.  
  29. int min_blob_sze = 400; // Minimum Blob size limit
  30. int max_blob_sze = 150000;
  31.  
  32. gray = cvCreateImage( cvGetSize(img), 8, 1 ); // To hold Grayscale Image
  33. thres = cvCreateImage( cvGetSize(img), 8, 1 ); // To hold OTSU thresholded Image
  34. prcs_flg = cvCreateImage( cvGetSize(img), 8, 1 ); // To hold Map of 'per Pixel' Flag to keep track while identifing Blobs
  35.  
  36. int clr_flg[img->width]; // Array representing elements of entire current row to assign Blob number
  37. int clrprev_flg[img->width]; // Array representing elements of entire previous row to assign Blob number
  38.  
  39. h = img->height; // Height and width of the Image
  40. w = img->width;
  41.  
  42. // img = cvLoadImage("cardtest.png",1);
  43. //Step : Convert Image captured from Camera to GrayScale
  44. //Info : Inbuit function from OpenCV
  45. //Note : Image from Camera and Grayscale are held using seperate "IplImage" objects
  46.  
  47. cvCvtColor(img,gray,CV_RGB2GRAY); // Convert RGB image to Gray
  48.  
  49.  
  50. //Step : Threshold the image using optimum Threshold value obtained from OTSU method
  51. //Info :
  52. //Note :
  53.  
  54. memset(ihist, 0, 256);
  55.  
  56. for(int j = 0; j < gray->height; ++j) // Use Histogram values from Gray image
  57. {
  58. uchar* hist = (uchar*) (gray->imageData + j * gray->widthStep);
  59. for(int i = 0; i < gray->width; i++ )
  60. {
  61. pos = hist[i]; // Check the pixel value
  62. ihist[pos] += 1; // Use the pixel value as the position/"Weight"
  63. }
  64. }
  65.  
  66. //Parameters required to calculate threshold using OTSU Method
  67. float prbn = 0.0; // First order cumulative
  68. float meanitr = 0.0; // Second order cumulative
  69. float meanglb = 0.0; // Global mean level
  70. int OPT_THRESH_VAL = 0; // Optimum threshold value
  71. float param1,param2; // Parameters required to work out OTSU threshold algorithm
  72. double param3 = 0.0;
  73.  
  74. //Normalise histogram values and calculate global mean level
  75. for(int i = 0; i < 256; ++i)
  76. {
  77. hist_val[i] = ihist[i] / (float)(w * h);
  78. meanglb += ((float)i * hist_val[i]);
  79. }
  80.  
  81. // Implementation of OTSU algorithm
  82. for (int i = 0; i < 255; i++)
  83. {
  84. prbn += (float)hist_val[i];
  85. meanitr += ((float)i * hist_val[i]);
  86.  
  87. param1 = (float)((meanglb * prbn) - meanitr);
  88. param2 = (float)(param1 * param1) /(float) ( prbn * (1.0f - prbn) );
  89.  
  90. if (param2 > param3)
  91. {
  92. param3 = param2;
  93. OPT_THRESH_VAL = i; // Update the "Weight/Value" as Optimum Threshold value
  94. }
  95. }
  96.  
  97. cvThreshold(gray,thres,OPT_THRESH_VAL,255,CV_THRESH_BINARY); //Threshold the Image using the value obtained from OTSU method
  98.  
  99.  
  100. //Step : Identify Blobs in the OTSU Thresholded Image
  101. //Info : Custom Algorithm to Identify blobs
  102. //Note : This is a complicated method. Better refer the presentation, documentation or the Demo
  103.  
  104. blob_count = 0; // Current Blob number used to represent the Blob
  105. CvPoint cornerA,cornerB; // Two Corners to represent Bounding Box
  106.  
  107. memset(clr_flg, 0, w); // Reset all the array elements ; Flag for tracking progress
  108. memset(clrprev_flg, 0, w);
  109.  
  110. cvZero(prcs_flg); // Reset all Process flags
  111.  
  112.  
  113. for( int y = 0; y < thres->height; ++y) //Start full scan of the image by incrementing y
  114. {
  115. uchar* prsnt = (uchar*) (thres->imageData + y * thres->widthStep);
  116. uchar* pntr_flg = (uchar*) (prcs_flg->imageData + y * prcs_flg->widthStep); // pointer to access the present value of pixel in Process flag
  117. uchar* scn_prsnt; // pointer to access the present value of pixel related to a particular blob
  118. uchar* scn_next; // pointer to access the next value of pixel related to a particular blob
  119.  
  120. for(int x = 0; x < thres->width; ++x ) //Start full scan of the image by incrementing x
  121. {
  122. int c = 0; // Number of edgels in a particular blob
  123.  
  124. if((prsnt[x] == 0) && (pntr_flg [x] == 0)) // If current pixel is black and has not been scanned before - continue
  125. {
  126. blob_count +=1; // Increment at the start of processing new blob
  127. clr_flg [x] = blob_count; // Update blob number
  128. pntr_flg [x] = 255; // Mark the process flag
  129.  
  130. n = 1; // Update pixel count of this particular blob / this iteration
  131.  
  132. cornerA.x = x; // Update Bounding Box Location for this particular blob / this iteration
  133. cornerA.y = y;
  134. cornerB.x = x;
  135. cornerB.y = y;
  136.  
  137. int lx,ly; // Temp location to store the initial position of the blob
  138. int belowx = 0;
  139.  
  140. bool checkbelow = true; // Scan the below row to check the continuity of the blob
  141.  
  142. ly=y;
  143.  
  144. bool below_init = 1; // Flags to facilitate the scanning of the entire blob once
  145. bool start = 1;
  146.  
  147. while(ly < h) // Start the scanning of the blob
  148. {
  149. if(checkbelow == true) // If there is continuity of the blob in the next row & checkbelow is set; continue to scan next row
  150. {
  151. if(below_init == 1) // Make a copy of Scanner pixel position once / initially
  152. {
  153. belowx=x;
  154. below_init = 0;
  155. }
  156.  
  157. checkbelow = false; // Clear flag before next flag
  158.  
  159. scn_prsnt = (uchar*) (thres->imageData + ly * thres->widthStep);
  160. scn_next = (uchar*) (thres->imageData + (ly+1) * thres->widthStep);
  161.  
  162. pntr_flg = (uchar*) (prcs_flg->imageData + ly * prcs_flg->widthStep);
  163.  
  164. bool onceb = 1; // Flag to set and check blbo continuity for next row
  165.  
  166. //Loop to move Scanner pixel to the extreme left pixel of the blob
  167. while((scn_prsnt[belowx-1] == 0) && ((belowx-1) > 0) && (pntr_flg[belowx-1]== 0))
  168. {
  169. cv_adjustBox(belowx,ly,cornerA,cornerB); // Update Bounding Box corners
  170. pntr_flg [belowx] = 255;
  171.  
  172. clr_flg [belowx] = blob_count;
  173.  
  174. n = n+1;
  175. belowx--;
  176. }
  177. //Scanning of a particular row of the blob
  178. for(lx = belowx; lx < thres->width; ++lx )
  179. {
  180. if(start == 1) // Initial/first row scan
  181. {
  182. cv_adjustBox(lx,ly,cornerA,cornerB);
  183. pntr_flg [lx] = 255;
  184.  
  185. clr_flg [lx] = blob_count;
  186.  
  187.  
  188. start = 0;
  189. if((onceb == 1) && (scn_next[lx] == 0)) //Check for the continuity
  190. {
  191. belowx = lx;
  192. checkbelow = true;
  193. onceb = 0;
  194. }
  195. }
  196. else if((scn_prsnt[lx] == 0) && (pntr_flg[lx] == 0)) //Present pixel is black and has not been processed
  197. {
  198. if((clr_flg[lx-1] == blob_count) || (clr_flg[lx+1] == blob_count)) //Check for the continuity with previous scanned data
  199. {
  200. cv_adjustBox(lx,ly,cornerA,cornerB);
  201.  
  202. pntr_flg [lx] = 255;
  203.  
  204. clr_flg [lx] = blob_count;
  205.  
  206. n = n+1;
  207.  
  208. if((onceb == 1) && (scn_next[lx] == 0))
  209. {
  210. belowx = lx;
  211. checkbelow = true;
  212. onceb = 0;
  213. }
  214. }
  215. else if((scn_prsnt[lx] == 0) && (clr_flg[lx-2] == blob_count)) // Check for the continuity with previous scanned data
  216. {
  217. cv_adjustBox(lx,ly,cornerA,cornerB);
  218.  
  219. pntr_flg [lx] = 255;
  220.  
  221. clr_flg [lx] = blob_count;
  222.  
  223. n = n+1;
  224.  
  225. if((onceb == 1) && (scn_next[lx] == 0))
  226. {
  227. belowx = lx;
  228. checkbelow = true;
  229. onceb = 0;
  230. }
  231. }
  232. // Check for the continuity with previous scanned data
  233. else if((scn_prsnt[lx] == 0) && ((clrprev_flg[lx-1] == blob_count) || (clrprev_flg[lx] == blob_count) || (clrprev_flg[lx+1] == blob_count)))
  234. {
  235. cv_adjustBox(lx,ly,cornerA,cornerB);
  236.  
  237. pntr_flg [lx] = 255;
  238.  
  239. clr_flg [lx] = blob_count;
  240.  
  241. n = n+1;
  242.  
  243. if((onceb == 1) && (scn_next[lx] == 0))
  244. {
  245. belowx = lx;
  246. checkbelow = true;
  247. onceb = 0;
  248. }
  249.  
  250. }
  251. else
  252. {
  253. continue;
  254. }
  255.  
  256. }
  257. else
  258. {
  259. clr_flg[lx] = 0; // Current pixel is not a part of any blob
  260. }
  261. } // End of scanning of a particular row of the blob
  262. }
  263. else // If there is no continuity of the blob in the next row break from blob scan loop
  264. {
  265. break;
  266. }
  267.  
  268. for(int q = 0; q < thres->width; ++q) // Blob numbers of current row becomes Blob number of previous row for the next iteration of "row scan" for this particular blob
  269. {
  270. clrprev_flg[q]= clr_flg[q];
  271. }
  272. ly++;
  273. }
  274. // End of the Blob scanning routine
  275.  
  276.  
  277. // At this point after scanning image data, A blob (or 'connected component') is obtained. We use this Blob for further analysis to confirm it is a Marker.
  278.  
  279.  
  280. // Get the Rectangular extent of the blob. This is used to estimate the span of the blob
  281. // If it too small, say only few pixels, it is too good to be true that it is a Marker. Thus reducing erroneous decoding
  282. rectw = abs(cornerA.x - cornerB.x);
  283. recth = abs(cornerA.y - cornerB.y);
  284. aspect_ratio = (double)rectw / (double)recth;
  285.  
  286. if((n > min_blob_sze) && (n < max_blob_sze)) // Reduces chances of decoding erroneous 'Blobs' as markers
  287. {
  288. if((aspect_ratio > 0.33) && (aspect_ratio < 3.0)) // Increases chances of identified 'Blobs' to be close to Square
  289. {
  290. // Good Blob; Mark it
  291. cvRectangle(img,cornerA,cornerB,CV_RGB(255,0,0),1);
  292. cvRectangle(thres,cornerA,cornerB,CV_RGB(255,0,0),1);
  293.  
  294. }
  295. else // Discard the blob data
  296. {
  297. blob_count = blob_count -1;
  298. }
  299. }
  300. else // Discard the blob data
  301. {
  302. blob_count = blob_count -1;
  303. }
  304.  
  305. }
  306. else // If current pixel is not black do nothing
  307. {
  308. continue;
  309. }
  310. } // End full scan of the image by incrementing x
  311. } // End full scan of the image by incrementing y
  312.  
  313.  
  314. cvShowImage("Camera",thres);
  315. cvShowImage("Camera1",img);
  316. cvDestroyWindow("Camera"); // Release various parameters
  317.  
  318. cvReleaseImage(&img);
  319. cvReleaseImage(&gray);
  320. cvReleaseImage(&thres);
  321. cvReleaseImage(&prcs_flg);
  322.  
  323. return 0;
  324.  
  325. }
  326.  
  327.  
  328. void cv_adjustBox(int x, int y, CvPoint& A, CvPoint& B)
  329. {
  330. if(x < A.x)
  331. A.x = x;
  332.  
  333. if(y < A.y)
  334. A.y = y;
  335.  
  336. if(x > B.x)
  337. B.x = x;
  338.  
  339. if(y > B.y)
  340. B.y = y;
  341. }
  342.  
  343.  
Compilation error #stdin compilation error #stdout 0s 0KB
stdin
Standard input is empty
compilation info
prog.cpp:1:16: fatal error: cv.h: No such file or directory
 #include <cv.h>
                ^
compilation terminated.
stdout
Standard output is empty