题目要求 |
程序代码 |
结果图片 |
要言妙道 |
从噪声图像中创建一个清晰的掩码。完成练习5后,保留图形中最大的图形区域。在图像的左上角设置一个指针,然后让他遍历图像。当你发现像素值为255的时候,存储其位置,然后对其漫水填充,新颜色值为100,。读出漫水填充法返回的连续区域,记录下其面积。如果图像中有另一个较大的区域,那么用0值对这个相对较小的区域进行颜色填充,然后删除已记录的面积。如果新的区域大于之前的区域,那么以0值填充之前的区域并删除他的位置。最后以颜色值255填充剩余的最大区域,显示结果。现在得到一个掩码,它是唯一的连续区域。
1 // OpenCVExerciseTesting.cpp : 定义控制台应用程序的入口点。 2 // 3 //D:\Work\Work_Programming\Source\Image\lena.jpg 4 5 6 #include "stdafx.h" 7 #include <cv.h> 8 #include <highgui.h> 9 #include <iostream> 10 using namespace cv; 11 using namespace std; 12 13 struct regionInfo 14 { 15 int x; 16 int y; 17 double area; 18 }; 19 20 //函数声明-->--->-->--->-->--->-->--->// 21 22 double FloodFillImage(IplImage * img, int x, int y, CvScalar newVal); 23 void DiscardTheSmallRegion(IplImage * img, regionInfo regionNow, regionInfo * largerRegion, regionInfo * smallRegion); 24 25 //<--<--<--<--<--<--<--<--<--函数声明// 26 27 28 int _tmain(int argc, _TCHAR* argv[]) 29 { 30 regionInfo largerRegion, smallRegion,regionNow; 31 largerRegion.area = DBL_MIN; 32 smallRegion.area = DBL_MAX; 33 34 const char * fileName1 = "D:\Work\Work_Programming\Source\Image\OpenCVExerciseImage\第5章\ExerciseResult_5-5.jpg"; 35 IplImage * src1 = cvLoadImage(fileName1, CV_LOAD_IMAGE_GRAYSCALE); 36 assert(src1); 37 38 39 cvNamedWindow("原始图像", 0); 40 cvNamedWindow("题目_a", 0); 41 42 cvShowImage("原始图像", src1); 43 44 //---------------------------a:开始--------------------------------// 45 46 IplImage * imgCopy = cvCloneImage(src1); 47 //cvZero(diff12); 48 //如果不用cvThreshold函数,得到的结果不是预期的,因为图片中有一部分像素值大于0但小y于255 49 //原本这张上一题保存的图片是阈值化过的,但保存后失真了,使用cvSaveImage的PNG格式的非压缩模式可以避免这个问题 50 cvThreshold(src1, imgCopy, 100, 255, CV_THRESH_BINARY); 51 52 int x = -1; 53 int y = -1; 54 double areaNow; 55 for (int h = 0; h < imgCopy->height;++h) 56 { 57 uchar* ptr = (uchar*)(imgCopy->imageData + h * imgCopy->widthStep); 58 for (int w = 0; w < imgCopy->width; ++w) 59 { 60 if (imgCopy->nChannels == 1) 61 { 62 if (ptr[w] == 255) 63 { 64 //起初将w赋值给了y,将h赋值给了x,导致结果不是自己想要的,此类问题很难找 65 x = w; 66 y = h; 67 areaNow = FloodFillImage(imgCopy, x, y, cvScalar(100)); 68 69 regionNow.x = x; 70 regionNow.y = y; 71 regionNow.area = areaNow; 72 73 DiscardTheSmallRegion(imgCopy,regionNow, &largerRegion, &smallRegion); 74 } 75 } 76 } 77 } 78 79 cvFloodFill(imgCopy, cvPoint(largerRegion.x, largerRegion.y), cvScalar(255), cvScalarAll(0.0), cvScalarAll(0.0), NULL, 8); 80 81 cvShowImage("题目_a", imgCopy); 82 83 84 //---------------------------a:结束--------------------------------// 85 86 cvWaitKey(0); 87 88 cvReleaseImage(&src1); 89 cvReleaseImage(&imgCopy); 90 91 cvDestroyWindow("原始图像"); 92 cvDestroyWindow("题目_a"); 93 94 return 0; 95 } 96 97 double FloodFillImage(IplImage * img,int x,int y,CvScalar newVal) 98 { 99 CvConnectedComp connectInfo; 100 int flags = 8; 101 cvFloodFill(img, cvPoint(x, y), newVal, cvScalarAll(2.0), cvScalarAll(0.0), &connectInfo, flags); 102 return connectInfo.area; 103 } 104 105 void DiscardTheSmallRegion(IplImage * img ,regionInfo regionNow, regionInfo * largerRegion, regionInfo * smallRegion) 106 { 107 if (regionNow.area >= largerRegion->area) 108 { 109 smallRegion->x = largerRegion->x; 110 smallRegion->y = largerRegion->y; 111 smallRegion->area = largerRegion->area; 112 113 largerRegion->x = regionNow.x; 114 largerRegion->y = regionNow.y; 115 largerRegion->area = regionNow.area; 116 } 117 else 118 { 119 smallRegion->x = regionNow.x; 120 smallRegion->y = regionNow.y; 121 smallRegion->area = regionNow.area; 122 } 123 124 if (smallRegion->area != DBL_MIN) 125 { 126 //FloodFillImage(img, smallRegion->x, smallRegion->y, cvScalar(0)); 127 cvFloodFill(img, cvPoint(smallRegion->x, smallRegion->y), cvScalar(0), cvScalarAll(0.0), cvScalarAll(0.0), NULL, 8); 128 } 129 }
因上一题保存图片时,使用jpg格式,而且cvSaveImage 的第三个参数使用的默认值,导致保存图片失真, 像素值除了0和255外还有其它,于是,得到的是右侧的 错误图片,漫水填充前重新阈值华或者上题保存时使用 非压缩方式可以避免此问题,保存图片的代码见后文 |
1 char * saveName = "E:\Testing\Image\SavePath\image_close.PNG"; 2 int params = 0; 3 cvSaveImage(saveName, dirtydiff, ¶ms);