用分水岭算法分割图片

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include<iostream>
using namespace cv;
using namespace std;


#define WINDOW_NAME "【程序窗口1】"
Mat g_maskImage, g_srcImage;
Point prevPt(-1,-1);
static void on_Mouse(int event,int x,int y,int flags,void*);

int main(int argc, char**argv)
{
	//【1】载入原图并显示,初始化掩膜和灰度图
	g_srcImage = imread("2.jpg",1); 
	imshow(WINDOW_NAME,g_srcImage);
	Mat srcImage, grayImage;
	g_srcImage.copyTo(srcImage);
	cvtColor(g_srcImage, g_maskImage,COLOR_BGR2GRAY);
	cvtColor(g_maskImage, grayImage, COLOR_GRAY2BGR);//也是灰度图啊,和上面那个g_maskImage没什么区别好像
	g_maskImage = Scalar:: all(0);
	//【2】设置鼠标回调函数
	setMouseCallback(WINDOW_NAME,on_Mouse,0);
	//waitKey(0);//这里要加这一个,不然不知道为什么上面的函数就不会运行了,不响应了,因为这样才能把窗口保持住,才能进行操作啊
	while (1)
	{
		//获取键值
		int c = waitKey(0);//当然这里有的话上面那个也可以没有了
		//若按键键值为ESC时,退出
		if ((char)c == 27)  break;
		//若按键值为2时,恢复原图
		if ((char)c == '2')
		{
			g_maskImage = Scalar::all(0);
			srcImage.copyTo(g_srcImage);
			imshow("image",g_srcImage);
		}
		//若检测到按键值为1或者空格,则进行处理
		if ((char)c == '1' || (char)c == ' ')
		{
			//定义一些参数
			int i, j, comCount = 0;
			vector<vector<Point>> contours;
			vector<Vec4i> hierarchy;
			//寻找轮廓
			findContours(g_maskImage,contours,hierarchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE);
			//轮廓为空时的处理
			if (contours.empty())
			{
				continue;
			}
			//复制掩模
			Mat maskImage(g_maskImage.size(),CV_32S);
			maskImage = Scalar::all(0);
			//循环绘制轮廓
			for (int index = 0; index >= 0; index = hierarchy[index][0], comCount++)
			{
				drawContours(maskImage, contours, index, Scalar::all(comCount+1), -1, 8, hierarchy, INT_MAX);
			}
			//comCount为0时的处理
			if (comCount == 0) continue;
			//生成随机颜色
			vector<Vec3b> colorTab;
			for (i = 0; i < comCount; i++)
			{
				int b = theRNG().uniform(0,255);
				int g = theRNG().uniform(0, 255);
				int r = theRNG().uniform(0, 255);
				colorTab.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
			}
			//计算处理时间并输出到窗口中
			double dTime = (double)getTickCount();
			watershed(srcImage,maskImage);
			dTime = (double)getTickCount() - dTime;
			printf("\t处理时间=%gms\n",dTime*1000./getTickFrequency());
			//双层循环,将分水岭图像遍历存入watershedImage中
			Mat watershedImage(maskImage.size(),CV_8UC3);
			for (i = 0; i < maskImage.rows; i++)
				for (j = 0; j < maskImage.cols; j++)
				{
					int index = maskImage.at<int>(i,j);
					if (index == -1)//区域间
					{
						watershedImage.at<Vec3b>(i, j) = Vec3b(255, 255, 255);
					}
					else if (index <= 0 || index > comCount)//应该是为标记的地方,也就是不确定的地方
						watershedImage.at<Vec3b>(i, j) = Vec3b(0,0,0);
					else//种子的位置?
						watershedImage.at<Vec3b>(i, j) = colorTab[index-1];
				}
				//混合灰度图和分水岭效果图并显示最终的窗口
				watershedImage = watershedImage*0.5 + grayImage*0.5;
				imshow("watershed transform", watershedImage);
		}
	}
	return 0;
}

效果图如下:

要转行人工智能的可以加下面这个公众号:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
分水岭算法是一种基于图像的分割方法,它可以将图像分成若干个不同的区域。下面是使用OpenCV库中的分水岭算法实现图像分割的Python代码示例: ```python import cv2 import numpy as np # 读取图像 img = cv2.imread('image.jpg') # 灰度化处理 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 对灰度图像进行阈值处理 ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU) # 对二值图像进行开运算(先腐蚀后膨胀) kernel = np.ones((3, 3), np.uint8) opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2) # 对开运算后的图像进行膨胀 sure_bg = cv2.dilate(opening, kernel, iterations=3) # 寻找前景区域 dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5) ret, sure_fg = cv2.threshold(dist_transform, 0.7*dist_transform.max(), 255, 0) # 找到未知区域 sure_fg = np.uint8(sure_fg) unknown = cv2.subtract(sure_bg, sure_fg) # 标记分水岭 ret, markers = cv2.connectedComponents(sure_fg) markers = markers + 1 markers[unknown==255] = 0 # 进行分水岭变换 markers = cv2.watershed(img, markers) # 给分割后的区域上色 img[markers == -1] = [255, 0, 0] # 显示分割结果 cv2.imshow('Segmented Image', img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 在这个代码中,首先读入图像,并将其转换为灰度图像。然后对灰度图像进行阈值处理,得到二值图像。接下来对二值图像进行开运算操作,以去除图片中的噪声。然后对开运算后的图像进行膨胀操作,以找到图像的背景。接着使用距离变换算法找到前景区域,并将其与背景区域合并,得到分水岭算法需要的标记。最后进行分水岭变换并给分割后的区域上色,即可得到图像分割的结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值