AbsDiff与cvMorphologyEx
我们先来学习图像求差的绝对值这个函数:AbsDiff,它的作用是:OpenCV 中计算两个数组差的绝对值的函数。
AbsDiffS:计算数组元素与数量之间差的绝对值,注意与上面不同的是数量value。
所有数组必须有相同的数据类型相同的大小(或ROI大小)
然后,我们学习形态学转换开运算cvMorphologyEx这个函数。
void cvMorphologyEx(const CvArr* src, CvArr* dst, CvArr* tmp, IplConvKernel* element, int operation, int iterations = 1);
参数说明:
src:输入图像
dst:输出图像
tmp:临时图像,某些操作会用到。需要使用tmp时,它应与原图像有同样的大小
element:结构元素
operation:形态操作的类型,有以下几种可用的类型:
-CV_MOP_OPEN开运算不需要临时图像
-CV_MOP_CLOSE闭运算不需要临时图像
-CV_MOP_GRADIENT形态梯度需要临时图像
-CV_MOP_TOPHAT“礼帽”src = dst情况下需要
-CV_MOP_BLACKHAT”黑帽“src = dst情况下需要
开运算:是先腐蚀然后再膨胀:dst = open(src, element) = dilate(erode(src, element), element)。开运算通常可以用来统计二值图像中的区域属,如已将显微镜载玻片上观察到的细胞图像作了阈值化处理,可以使用开运算将相邻的细胞分离开来,然后再计算图像中的区域细胞数目。
闭运算:是先膨胀然后再腐蚀:dst = close(src, element) = erode(dilate(src, element), element)。在大多数好的连通区域分析算法中,都会用到闭运算来除去噪声引起的区域。对于连通区域分析,通常采用腐蚀或闭运算来消除纯粹由噪声引起的部分,然后用开运算来连接邻近的区域。
形态学梯度:膨胀图像减去腐蚀图像:dst = dilate(src, element) - erode(src, element)。形态学梯度操作能描述图像亮度变化的剧烈程度。当想突出亮度区域的外围时,通常可使用形态学梯度,这样可以把高亮的看成一个整体。因为从原区域的膨胀中减去了原区域的收缩,所以留下了完整的外围边缘。
礼帽操作:dst = src - open(src, element)
黑帽操作:dst = close(src, element) - src
这两个操作分别用于分离比邻近的点亮或暗的一些斑块。
题目描述:
拍一张某场景的图片,然后相机不动,在此场景中心位置放一个杯子,再拍一张图片,将其载入电脑并转换为8位灰度图像
a、求其差的绝对值并显示结果,他应该是一个带有噪声的杯子的掩码,
b、对结果图像进行二值化操作,剔除噪声的同时并保留鼠标,超过阈值的像素应设为255
c、在图像上进行CV_MOP_OPEN操作,进一步清除噪声
代码:
#include
#include
#include
using namespace cv;
using namespace std;
//函数声明-->--->-->--->-->--->-->--->//
//<--<--<--<--<--<--<--<--<--函数声明//
int main()
{
const char * fileName1 = "D:\\VC98\\C++项目\\opencv\\cvMorphologyEx_1\\cvMorphologyEx_1\\cup.jpg";
const char * fileName2 = "D:\\VC98\\C++项目\\opencv\\cvMorphologyEx_1\\cvMorphologyEx_1\\cup1.jpg";
IplImage * src1 = cvLoadImage(fileName1, CV_LOAD_IMAGE_GRAYSCALE);
IplImage * src2 = cvLoadImage(fileName2, CV_LOAD_IMAGE_GRAYSCALE);
assert(src1);
assert(src2);
//IplImage * img = cvCreateImage(cvSize(100, 100), IPL_DEPTH_8U, 1);
//assert(img);
//cvZero(img);
//cvSetReal2D(img, 49, 49, 255);
cvNamedWindow("原始图像1", 0);
cvNamedWindow("原始图像2", 0);
cvNamedWindow("题目_a", 0);
cvNamedWindow("题目_b", 0);
cvNamedWindow("题目_c", 0);
//cvNamedWindow("题目_d", 0);
/*char * imageName = "E:\\Testing\\Image\\ExerciseWindow.jpg";
cvSaveImage(imageName, img);*/
cvShowImage("原始图像1", src1);
cvShowImage("原始图像2", src2);
//---------------------------a:开始--------------------------------//
IplImage * diff12 = cvCloneImage(src1);
cvZero(diff12);
cvAbsDiff(src1, src2, diff12);
cvShowImage("题目_a", diff12);
cvSaveImage("result.jpg",diff12);
/*char * saveName = "E:\\Testing\\Image\\SavePath\\diff12.jpg";
cvSaveImage(saveName, diff12);*/
//---------------------------a:结束--------------------------------//
//---------------------------b:开始--------------------------------//
IplImage * cleandiff = cvCloneImage(diff12);
cvZero(cleandiff);
//针对有很强照明或反射梯度的图像,需要根据梯度进行阈值化时,自适应技术非常有用,看图5-24的处理结果对比很明显
cvThreshold(diff12, cleandiff, 64, 255, CV_THRESH_BINARY);
cvShowImage("题目_b", cleandiff);
cvSaveImage("result1.jpg",cleandiff);
/*saveName = "E:\\Testing\\Image\\SavePath\\image_open.jpg";
cvSaveImage(saveName, cleandiff);*/
//---------------------------b:结束--------------------------------//
//---------------------------c:开始--------------------------------//
IplImage * dirtydiff = cvCloneImage(cleandiff);
cvZero(dirtydiff);
IplConvKernel * kernel = cvCreateStructuringElementEx(3, 3, 1, 1, CV_SHAPE_RECT);
cvMorphologyEx(cleandiff, dirtydiff, NULL, kernel, CV_MOP_OPEN,2);
cvShowImage("题目_c", dirtydiff);
cvSaveImage("result2.jpg",dirtydiff);
/*saveName = "E:\\Testing\\Image\\SavePath\\image_close.jpg";
cvSaveImage(saveName, dirtydiff);*/
//---------------------------c:结束--------------------------------//
cvWaitKey(0);
cvReleaseImage(&src1);
cvReleaseImage(&src2);
cvReleaseImage(&diff12);
cvReleaseImage(&cleandiff);
cvReleaseImage(&dirtydiff);
cvDestroyWindow("原始图像1");
cvDestroyWindow("原始图像2");
cvDestroyWindow("题目_a");
cvDestroyWindow("题目_b");
cvDestroyWindow("题目_c");
//cvDestroyWindow("题目_d");
return 0;
}
结果:
输入的两张图片:
题目_a:
题目_b:
题目_c: