├── README.md ├── ruisheng └── ruisheng.cpp /README.md: -------------------------------------------------------------------------------- 1 | # Camera-lens-glass 2 | 摄像头玻璃缺陷检测2015.11.05 3 | -------------------------------------------------------------------------------- /ruisheng: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/njuzpw/Camera-lens-glass/HEAD/ruisheng -------------------------------------------------------------------------------- /ruisheng.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "cv.h" 3 | #include "highgui.h" 4 | #include 5 | #include 6 | using namespace std; 7 | using namespace cv; 8 | 9 | #define debug 10 | #define PI 3.1415926 11 | #define providing 12 | 13 | 14 | // string fold_path = "./1124/"; 15 | // string img_name = "1.bmp"; 16 | // string img_path = fold_path + img_name; 17 | string write_path = "../Camera-lens-glassFiles/save/"; 18 | string providing_path = "../Camera-lens-glassFiles/providingPics/"; 19 | string pic_name; 20 | const double LenOfRoi =1.3527;//ROI区域的直径为1.3527毫米 21 | double LenOfOnePixel = 0; 22 | double len_onePixel = 3.45;//像素当量3.63微米 23 | 24 | struct area_pos 25 | { 26 | double areaValue; 27 | int index; 28 | }; 29 | 30 | 31 | 32 | bool comp(const area_pos& s1,const area_pos& s2) 33 | { 34 | if(s1.areaValue >= s2.areaValue) 35 | return true; 36 | else 37 | return false; 38 | } 39 | 40 | 41 | void show(const vector& vec) 42 | { 43 | for (int i = 0; i != vec.size(); ++i) 44 | { 45 | cout << "(" << vec[i].x << "," << vec[i].y << ")" << endl; 46 | } 47 | } 48 | 49 | void showDefect(Mat& image, Rect& rect, const Scalar& color,int temp) 50 | { 51 | Point p1,p2; 52 | p1.x = rect.x; 53 | p1.y = rect.y; 54 | p2.x = p1.x + rect.width; 55 | p2.y = p1.y + rect.height; 56 | cv:: rectangle(image,p1,p2,color); 57 | char value[10]; 58 | sprintf(value, "%d", temp); 59 | // cout << "value = " << value << endl; 60 | putText(image, string(value),p1,FONT_HERSHEY_SIMPLEX,0.2,Scalar(255,0,0)); 61 | } 62 | 63 | int DetectDefect(Mat src,Mat mask,Mat res_thre){ 64 | 65 | Mat resultShow = src.clone(); 66 | cvtColor(resultShow,resultShow,CV_GRAY2BGR); 67 | // erode(mask,mask,Mat()); 68 | // erode(mask,mask,Mat()); 69 | // erode(mask,mask,Mat()); 70 | cvtColor(mask,mask,CV_BGR2GRAY); 71 | Mat res_thre_out = res_thre.clone(); 72 | #ifdef debug 73 | imshow("result",res_thre_out); 74 | imwrite(write_path +"thre.bmp",res_thre_out); 75 | waitKey(); 76 | #endif 77 | 78 | vector > contours; 79 | vector hierarchy; 80 | findContours(res_thre_out,contours,hierarchy,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE ); 81 | //cout< minRect( contours.size() ); 89 | vector flags( contours.size(),1); 90 | 91 | for( int i = 0; i != contours.size(); ++i ){ 92 | minRect[i] = minAreaRect( Mat(contours[i]) ); 93 | if(contourArea(contours[i]) < 1) 94 | 95 | flags[i] = 0; 96 | } 97 | if( !countNonZero(Mat(flags)) ) 98 | { cout<< "no defect again " << endl; 99 | return -1; 100 | } 101 | else{ 102 | res_thre_out.setTo(cv::Scalar::all(0)); 103 | vector > DefectContours; 104 | for( int i = 0; i != minRect.size(); ++i ){ 105 | if(flags[i]) 106 | DefectContours.push_back(contours[i]); 107 | } 108 | cv::drawContours(res_thre_out, DefectContours, -1, Scalar::all(255), CV_FILLED); 109 | #ifdef debug 110 | imshow("DefectContours",res_thre_out); 111 | imwrite(write_path +"DefectContours.bmp",res_thre_out); 112 | waitKey(); 113 | #endif 114 | vector area(DefectContours.size()); 115 | vector showRect(DefectContours.size()); 116 | double sum_piexl = 0; 117 | for(size_t i = 0; i != DefectContours.size(); i++) 118 | { 119 | //area[i].areaValue=(double)contourArea(DefectContours[i])*LenOfOnePixel*LenOfOnePixel*4.0; 120 | area[i].areaValue=(double)contourArea(DefectContours[i])*len_onePixel*len_onePixel; 121 | sum_piexl+=area[i].areaValue; 122 | area[i].index = i; 123 | //cout << "defect_area : "< showRectTop10(ShowTop10); 134 | for(int i = 0; i= 0) ? (j - halfwidth) : 0; 181 | int ystart = (i - halfheight >= 0) ? (i - halfheight) : 0; 182 | int xend = (j + halfwidth < src.cols) ? (j + halfwidth) : src.cols - 1; 183 | int yend = (i + halfheight < src.rows) ? (i + halfheight) : src.rows - 1; 184 | int count(0); 185 | int sum(0); 186 | for(int m = xstart; m <= xend; ++m) 187 | for(int n = ystart; n <= yend; ++n) 188 | { 189 | if(src.at(n,m) != 0) 190 | { 191 | sum += src.at(n,m); 192 | ++count; 193 | } 194 | } 195 | if(count == 0) 196 | mean.at(i,j) = 0; 197 | else 198 | mean.at(i,j) = sum / count; 199 | } 200 | #ifdef debug 201 | imshow("mean",mean); 202 | #endif 203 | } 204 | 205 | 206 | void my_adaptiveThreshold(Mat src,Mat& dst,int blockWidth,int blockHeight,int c) 207 | { 208 | Mat mean = Mat::zeros(src.size(),CV_8UC1); 209 | my_boxFilter(src,mean,blockWidth,blockHeight); 210 | for(int i = 0; i != src.rows; ++i) 211 | for(int j = 0; j != src.cols; ++j) 212 | { 213 | if( c > 0) 214 | { 215 | if(int(src.at(i,j)) - int(mean.at(i,j)) >= c) 216 | dst.at(i,j) = 255; 217 | else 218 | dst.at(i,j) = 0; 219 | } 220 | if( c < 0) 221 | { 222 | if(int(src.at(i,j)) - int(mean.at(i,j)) <= c) 223 | dst.at(i,j) = 255; 224 | else 225 | dst.at(i,j) = 0; 226 | } 227 | } 228 | } 229 | 230 | Mat get_pic_dis_withCircleSeedPoints(Mat res, Mat orign) 231 | { 232 | Mat orignSave = orign.clone(); 233 | erode(res,res,Mat()); 234 | erode(res,res,Mat()); 235 | erode(res,res,Mat()); 236 | erode(res,res,Mat()); 237 | erode(res,res,Mat()); 238 | erode(res,res,Mat()); 239 | erode(res,res,Mat()); 240 | erode(res,res,Mat()); 241 | erode(res,res,Mat()); 242 | erode(res,res,Mat()); 243 | erode(res,res,Mat()); 244 | erode(res,res,Mat()); 245 | erode(res,res,Mat()); 246 | vector > CircleSeedPoints; 247 | cvtColor(res, res, CV_BGR2GRAY); 248 | findContours(res, CircleSeedPoints, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); 249 | for (int i = 0; i < CircleSeedPoints[0].size(); ++i) 250 | { 251 | if(orign.at(CircleSeedPoints[0][i].y,CircleSeedPoints[0][i].x) == 0) 252 | floodFill(orign, CircleSeedPoints[0][i], Scalar(255, 255, 255)); 253 | } 254 | Mat pic_dis = orign - orignSave; 255 | #ifdef debug 256 | imshow("get_pic_dis_withCircleSeedPoints",pic_dis); 257 | imwrite(write_path + "get_pic_dis_withCircleSeedPoints.bmp", pic_dis); 258 | imwrite(write_path + "circle_seedPoints_floodresult.bmp", orign); 259 | #endif 260 | return pic_dis; 261 | } 262 | 263 | Mat findCircleMask(const Mat& _src) 264 | { 265 | Mat src, src_gray; 266 | //src = imread(img_path, 0); 267 | src = _src.clone(); 268 | //pyrDown(src, src); 269 | //pyrDown(src, src); 270 | threshold(src, src, 0, 255, THRESH_BINARY | CV_THRESH_OTSU); 271 | //threshold(src, src, 100,255, THRESH_BINARY); 272 | Mat binary_src = src.clone(); 273 | Mat flood_binary_src = src.clone(); 274 | Mat flood_binary_src_withCircleSeedPoints = src.clone(); 275 | #ifdef debug 276 | imshow("src", src); 277 | imwrite(write_path + "src.bmp", src); 278 | #endif 279 | cvtColor(src, src, CV_GRAY2BGR); 280 | if (!src.data) 281 | { 282 | return Mat(); 283 | } 284 | cvtColor(src, src_gray, CV_BGR2GRAY); 285 | GaussianBlur(src_gray, src_gray, Size(9, 9), 2, 2); 286 | vector circles; 287 | HoughCircles(src_gray, circles, CV_HOUGH_GRADIENT, 1, 10, 200, 100, 0, 0); 288 | for (size_t i = 0; i < circles.size(); i++) 289 | { 290 | Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); 291 | int radius = cvRound(circles[i][2]); 292 | circle(src, center, 3, Scalar(0, 0, 255), -1, 8, 0); 293 | circle(src, center, radius, Scalar(0, 0, 255), 1, 8, 0); 294 | } 295 | Point center; 296 | int radius(INT_MAX); 297 | assert(circles.size()); 298 | for (int i = 0; i != circles.size(); ++i) 299 | { 300 | if (circles[i][2] < radius) 301 | { 302 | radius = circles[i][2]; 303 | center.x = circles[i][0]; 304 | center.y = circles[i][1]; 305 | } 306 | } 307 | LenOfOnePixel = LenOfRoi*1000/(2.0*(double)radius*2.0); 308 | //cout << "randius" << radius << endl; 309 | //cout << "(" << center.x << "," << center.y << ")" << endl< seedPoints; 311 | Point TempSeedPoint; 312 | int dis = int(radius / 2 / 1.414); 313 | //1 314 | TempSeedPoint.x = center.x - dis; 315 | TempSeedPoint.y = center.y - dis; 316 | seedPoints.push_back(TempSeedPoint); 317 | //2 318 | TempSeedPoint.x = center.x; 319 | TempSeedPoint.y = center.y - dis; 320 | seedPoints.push_back(TempSeedPoint); 321 | //3 322 | TempSeedPoint.x = center.x + dis; 323 | TempSeedPoint.y = center.y - dis; 324 | seedPoints.push_back(TempSeedPoint); 325 | //4 326 | TempSeedPoint.x = center.x + dis; 327 | TempSeedPoint.y = center.y; 328 | seedPoints.push_back(TempSeedPoint); 329 | //5 330 | TempSeedPoint.x = center.x + dis; 331 | TempSeedPoint.y = center.y + dis; 332 | seedPoints.push_back(TempSeedPoint); 333 | //6 334 | TempSeedPoint.x = center.x; 335 | TempSeedPoint.y = center.y + dis; 336 | seedPoints.push_back(TempSeedPoint); 337 | //7 338 | TempSeedPoint.x = center.x - dis; 339 | TempSeedPoint.y = center.y + dis; 340 | seedPoints.push_back(TempSeedPoint); 341 | //8 342 | TempSeedPoint.x = center.x - dis; 343 | TempSeedPoint.y = center.y; 344 | seedPoints.push_back(TempSeedPoint); 345 | 346 | for (int i = 0; i != seedPoints.size(); ++i) 347 | { 348 | circle(src, seedPoints[i], 3, Scalar(0, 255, 0), -1, 8, 0); 349 | } 350 | #ifdef debug 351 | imshow("pointsPosition", src); 352 | imwrite(write_path + "pointsPosition.bmp", src); 353 | #endif 354 | 355 | for (int i = 0; i != seedPoints.size(); ++i) 356 | { 357 | //if(flood_binary_src.at(seedPoints[i].y,seedPoints[i].x) == 0); 358 | floodFill(flood_binary_src, seedPoints[i], Scalar(255, 255, 255)); 359 | } 360 | #ifdef debug 361 | imshow("floodresults", flood_binary_src); 362 | imwrite(write_path + "floodresults.bmp", flood_binary_src); 363 | #endif 364 | Mat pic_dis = flood_binary_src - binary_src; 365 | 366 | //ÏÂÃæÊÇ»ñÈ¡Ëùº¬ÐÎ×´µÄÍâ½ÓÔ² 367 | Point2f enclosing_cecter; 368 | float enclosing_radius(0); 369 | threshold(pic_dis, pic_dis, 150, 255, THRESH_BINARY); 370 | #ifdef debug 371 | imwrite(write_path + "pic_dis.bmp", pic_dis); 372 | //imshow("pic_dis", pic_dis); 373 | #endif 374 | 375 | //**********************according Circumcircle to get mask**************************** 376 | vector< vector > cont; 377 | findContours(pic_dis, cont, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); 378 | Mat canvas = Mat::zeros(src.size(), CV_8UC3); 379 | Mat ans = canvas.clone(); 380 | drawContours(canvas, cont, -1, Scalar(255, 255, 255)); 381 | minEnclosingCircle(cont[0], enclosing_cecter, enclosing_radius); 382 | cout << "enclosing_radius" << len_onePixel * enclosing_radius << endl; 383 | circle(ans, enclosing_cecter, enclosing_radius, Scalar(255, 255, 255), -1, 8, 0); 384 | threshold(ans, ans, 150, 255, THRESH_BINARY); 385 | #ifdef debug 386 | imwrite(write_path + "ans.bmp",ans); 387 | //imshow("ans", ans); 388 | #endif 389 | //show(seedPoints); 390 | return ans; 391 | //*********************************************************************************** 392 | 393 | //**********************according convexHull to get mask***************************** 394 | Mat pic_disCopy = pic_dis.clone(); 395 | pic_disCopy = get_pic_dis_withCircleSeedPoints(ans,flood_binary_src_withCircleSeedPoints); 396 | vector< vector > convexHullcont; 397 | vector hierarchy; 398 | findContours(pic_disCopy,convexHullcont,hierarchy,CV_RETR_TREE,CV_CHAIN_APPROX_SIMPLE, Point(0, 0)); 399 | vector > hull(convexHullcont.size()); 400 | for( int i = 0; i < convexHullcont.size(); i++ ) 401 | { 402 | convexHull( Mat(convexHullcont[i]), hull[i], false ); 403 | } 404 | Mat drawing = Mat::zeros(pic_disCopy.size(), CV_8UC3 ); 405 | for(int i = 0; i != convexHullcont.size(); ++i) 406 | { 407 | drawContours( drawing, hull, i, Scalar(255,255,255), -1, 8, vector(), 0, Point() ); 408 | } 409 | #ifdef debug 410 | imshow("drawing",drawing); 411 | imwrite(write_path + "drawing.bmp",drawing); 412 | //waitKey(0); 413 | #endif 414 | //pyrUp(drawing,drawing); 415 | //pyrUp(drawing,drawing); 416 | return drawing; 417 | } 418 | 419 | void getRidOfThreshEdges(Mat& thresholdResult) 420 | { 421 | #ifdef debug 422 | imshow("thresholdResult",thresholdResult); 423 | #endif 424 | Point2f center; 425 | float radius(0); 426 | Mat src = thresholdResult.clone(); 427 | Mat cont_src = thresholdResult.clone(); 428 | Mat cont_canvas = Mat::zeros(thresholdResult.size(),CV_8UC3); 429 | vector< vector > cont; 430 | findContours(cont_src,cont,CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); 431 | minEnclosingCircle(cont[0],center,radius); 432 | Mat canvas = Mat::zeros(thresholdResult.size(),CV_8UC3); 433 | circle(canvas,center,radius,Scalar(0,255,0),-1,8,0); 434 | #ifdef debug 435 | imshow("fill_canva",canvas); 436 | #endif 437 | return; 438 | } 439 | 440 | void erodeLoop(Mat& pic,int looptime) 441 | { 442 | for(int i = 0; i <= looptime; ++i) 443 | erode(pic,pic,Mat()); 444 | return; 445 | } 446 | 447 | Mat findThreshResult(Mat src,Mat mask) 448 | { 449 | cvtColor(mask, mask, CV_BGR2GRAY); 450 | #ifdef debug 451 | imshow("mask", mask); 452 | #endif 453 | Mat and_img = Mat::zeros(src.size(),CV_8UC1); 454 | //erode(mask, mask, Mat()); 455 | //erode(mask, mask, Mat()); 456 | bitwise_and(mask, src, and_img); 457 | 458 | // Mat mean = Mat::zeros(and_img.size(),CV_8UC1); 459 | // my_boxFilter(and_img,mean,7,7); 460 | 461 | #ifdef debug 462 | imwrite(write_path + "seg_img.bmp", and_img); 463 | imshow("seg_img", and_img); 464 | #endif 465 | //adaptiveThreshold(and_img, and_img, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 7, -3); 466 | Mat adaptiveThresholdResult1 = Mat::zeros(src.size(),CV_8UC1); 467 | Mat adaptiveThresholdResult2 = Mat::zeros(src.size(),CV_8UC1); 468 | //my_adaptiveThreshold(and_img,adaptiveThresholdResult,11,11,-3); 469 | adaptiveThreshold(and_img,adaptiveThresholdResult1,255,ADAPTIVE_THRESH_MEAN_C,THRESH_BINARY,11,-5); 470 | adaptiveThreshold(and_img,adaptiveThresholdResult2,255,ADAPTIVE_THRESH_MEAN_C,THRESH_BINARY_INV,11,5); 471 | Mat adaptiveThresholdResult = Mat::zeros(src.size(),CV_8UC1); 472 | adaptiveThresholdResult = adaptiveThresholdResult1 | adaptiveThresholdResult2; 473 | //dilate(adaptiveThresholdResult,adaptiveThresholdResult,Mat()); 474 | //erode(adaptiveThresholdResult,adaptiveThresholdResult,Mat()); 475 | Mat res; 476 | // erode(mask, mask, Mat()); 477 | // erode(mask, mask, Mat()); 478 | erodeLoop(mask,4); 479 | bitwise_and(adaptiveThresholdResult, mask, res); 480 | #ifdef debug 481 | //dilate(adaptiveThresholdResult,adaptiveThresholdResult,Mat()); 482 | //dilate(res,res,Mat()); 483 | imshow("and_img", adaptiveThresholdResult); 484 | imwrite(write_path + "and_img_1.bmp",adaptiveThresholdResult); 485 | imwrite(write_path + "and_img.bmp",res); 486 | imshow("res", res); 487 | imwrite(write_path + "res.bmp",res); 488 | #endif 489 | return res; 490 | } 491 | 492 | string seprateName(const string& s) 493 | { 494 | string ans; 495 | for(int i = s.size() - 1; i >= 0; --i) 496 | { 497 | if(s[i] == '/') 498 | break; 499 | ans.push_back(s[i]); 500 | } 501 | reverse(ans.begin(),ans.end()); 502 | return ans; 503 | } 504 | 505 | 506 | void process(char** argv) 507 | { 508 | Mat src = imread(argv[1], 0); 509 | pic_name = seprateName(string(argv[1])); 510 | cout< whitePos; 532 | // for(int i = 0; i != src.rows;++i) 533 | // for(int j = 0; j != src.cols; ++j) 534 | // { 535 | // if(src.at(i,j) == 255) 536 | // whitePos.push_back(Point(j,i)); 537 | // } 538 | // Point2f center; 539 | // float radius; 540 | // minEnclosingCircle(whitePos,center,radius); 541 | // Mat canvas = Mat::zeros(src.size(),CV_8UC1); 542 | // circle(canvas, center, radius, Scalar(255, 255, 255), -1, 8, 0); 543 | // imshow("drawCanvas",canvas); 544 | // return canvas; 545 | // } 546 | 547 | int main(int argc,char** argv) 548 | { 549 | double t = (double)getTickCount(); 550 | process(argv); 551 | t = ((double)getTickCount() - t)/getTickFrequency(); 552 | cout <<"program time = " << t*1000.0 << "ms" << endl; 553 | #ifdef debug 554 | waitKey(0); 555 | #endif 556 | return 0; 557 | } 558 | 559 | --------------------------------------------------------------------------------