基于图像分块的图像瓜分
基于图像分块的图像分割阈处理直观、实现简单且计算速度快,因此图像阈处理在图像分割中处于核心地位。阈处理
基于图像分块的图像分割
阈值处理直观、实现简单且计算速度快,因此图像阈值处理在图像分割中处于核心地位。阈值处理可分为全局阈值处理和局部阈值处理(可变阈值处理)。本人在http://blog.csdn.net/wuhaibing_cver/article/details/8473498一文中介绍了基于OTSU的全局阈值处理,由于噪声和非均匀光照对阈值处理算法的性能起着重要作用,所以有时候利用全局阈值处理进行图像分割往往会导致错误的分割结果。
基于图像分块的局部图像分割。图像分块属于可变阈值处理中简单的方法,这种方法可补偿光照的不均匀性。选择的矩形要足够小,以便每个矩形的光照都是近视均匀的。需要强调的是,不能把图像分的过细,因为细分可能只包含物体或背景像素。
下面给出该方法的源代码,使用的工具为VS2008+OpenCV2.0.
- #include <cv.h>
- #include <highgui.h>
- #include <iostream>
-
- using namespace std;
-
- int otsu(const IplImage *image)
- {
- assert(NULL != image);
-
- int width = image->width;
- int height = image->height;
- int x=0,y=0;
- int pixelCount[256];
- float pixelPro[256];
- int i, j, pixelSum = width * height, threshold = 0;
-
- uchar* data = (uchar*)image->imageData;
-
- //初始化
- for(i = 0; i < 256; i++)
- {
- pixelCount[i] = 0;
- pixelPro[i] = 0;
- }
-
- //统计灰度级中每个像素在整幅图像中的个数
- for(i = y; i < height; i++)
- {
- for(j = x;j <width;j++)
- {
- pixelCount[data[i * image->widthStep + j]]++;
- }
- }
-
-
- //计算每个像素在整幅图像中的比例
- for(i = 0; i < 256; i++)
- {
- pixelPro[i] = (float)(pixelCount[i]) / (float)(pixelSum);
- }
-
- //经典ostu算法,得到前景和背景的分割
- //遍历灰度级[0,255],计算出方差最大的灰度值,为最佳阈值
- float w0, w1, u0tmp, u1tmp, u0, u1, u,deltaTmp, deltaMax = 0;
- for(i = 0; i < 256; i++)
- {
- w0 = w1 = u0tmp = u1tmp = u0 = u1 = u = deltaTmp = 0;
-
- for(j = 0; j < 256; j++)
- {
- if(j <= i) //背景部分
- {
- //以i为阈值分类,第一类总的概率
- w0 += pixelPro[j];
- u0tmp += j * pixelPro[j];
- }
- else //前景部分
- {
- //以i为阈值分类,第二类总的概率
- w1 += pixelPro[j];
- u1tmp += j * pixelPro[j];
- }
- }
-
- u0 = u0tmp / w0; //第一类的平均灰度
- u1 = u1tmp / w1; //第二类的平均灰度
- u = u0tmp + u1tmp; //整幅图像的平均灰度
- //计算类间方差
- deltaTmp = w0 * (u0 - u)*(u0 - u) + w1 * (u1 - u)*(u1 - u);
- //找出最大类间方差以及对应的阈值
- if(deltaTmp > deltaMax)
- {
- deltaMax = deltaTmp;
- threshold = i;
- }
- }
- //返回最佳阈值;
- return threshold;
- }
-
- int main()
- {
- char* filename = "D:\\technology\\CV\\Databases\\image\\septagon_noisy_shaded.tif";
- IplImage* src_image = cvLoadImage(filename,0);
- if(!src_image)
- return -1;
-
- cvNamedWindow("src",0);
- cvShowImage("src",src_image);
-
- CvSize size = cvGetSize(src_image);
- int height = size.height, width = size.width;
- IplImage* bi_image = cvCreateImage(size,8,1);
-
- #if 0
-
- int threshold = otsu(src_image);
- cout<<"threshold: "<<threshold<<endl;
-
- cvThreshold(src_image,bi_image,threshold,255,CV_THRESH_BINARY);
-
- #else
- int rows = 2, cols = 3;
- //第i行,第j列的左上角topleft,右下角bottomright
- CvPoint topleft,bottomright;
- CvRect rect;
- IplImage* roi_image = 0;
- IplImage* bi_roi = 0;
- for(int i=0;i<rows;i++)
- {
- for(int j=0;j<cols;j++)
- {
- topleft.x = cvRound(j*width/(float)cols);
- topleft.y = cvRound(i*height/(float)rows);
- bottomright.x = cvRound((j+1)*width/(float)cols);
- bottomright.y = cvRound((i+1)*height/(float)rows);
- int w = bottomright.x-topleft.x;
- int h = bottomright.y-topleft.y;
-
- rect = cvRect(topleft.x,topleft.y,w,h);
- cvSetImageROI(src_image,rect);
- cvSetImageROI(bi_image,rect);
- roi_image = cvCreateImage(cvSize(w,h),8,1);
- bi_roi = cvCreateImage(cvSize(w,h),8,1);
- cvCopy(src_image,roi_image);
- cvResetImageROI(src_image);
-
- int threshold = otsu(roi_image);
- cvThreshold(roi_image,bi_roi,threshold,255,CV_THRESH_BINARY);
- cvCopy(bi_roi,bi_image);
-
- cvResetImageROI(bi_image);
- cvReleaseImage(&bi_roi);
- cvReleaseImage(&roi_image);
- }
- }
-
- #endif
-
- cvNamedWindow("dst",0);
- cvShowImage("dst",bi_image);
-
- cvWaitKey(0);
-
- cvReleaseImage(&src_image);
- cvReleaseImage(&bi_image);
- cvDestroyWindow("src");
- cvDestroyWindow("dst");
-
- return 0;
- }
源图像如下,可以看出该图像光照不均匀。
当把图像分块成2行3列,即rows = 2, cols = 3时,分割结果如下,可以看到该分割结果符合我们的要求。
当rows = 3, cols = 4时,由于图像分的过细,某些局部只包含了物体或背景,导致分割失败,如下图所示: