基于距离变换和分水岭算法的图像分割(图像变换 )

// 加载图像
Mat src = imread( "../data/cards.png");
// 成功加载
if (!src. data)
return -1;
// 显示图像
imshow( "Source Image", src);


如果我们用白色背景图像,转换它的黑色是好的。这将有助于我们desciminate(discriminate 区分)前景对象时更容易,运用距离变换。

//改变背景颜色白色到黑色。 距离变换更方便。
for( int x = 0; x < src.rows; x++ ) {
for( int y = 0; y < src. cols; y++ ) {
if ( src.at< Vec3b>(x, y) == Vec3b(255,255,255) ) {
src.at< Vec3b>(x, y)[0] = 0;
src.at< Vec3b>(x, y)[1] = 0;
src.at< Vec3b>(x, y)[2] = 0;
}
}
}
// 现实输出图像
imshow( "Black Background Image", src);


// Create a kernel that we will use for accuting/sharpening our image 滤波
Mat kernel = ( Mat_<float>(3,3) <<
1, 1, 1,
1, -8, 1,
1, 1, 1); // an approximation of second derivative, a quite strong kernel 二阶导数 一个强的核
// do the laplacian filtering as it is
// well, we need to convert everything in something more deeper then CV_8U
// because the kernel has some negative values, 负值
// and we can expect in general to have a Laplacian image with negative values
// BUT a 8bits unsigned int (the one we are working with) can contain values from 0 to 255
// so the possible negative number will be truncated
//因为内核有一些负值,我们一般可以得到一个负值的拉普拉斯图像。
//但8bits unsigned int(我们的工作)可以包含0到255的值,因此可能负值将被截断
Mat imgLaplacian;
Mat sharp = src; // copy source image to another temporary one
filter2D(sharp, imgLaplacian, CV_32F, kernel);
src. convertTo(sharp, CV_32F);
Mat imgResult = sharp - imgLaplacian;
// convert back to 8bits gray scale
imgResult. convertTo(imgResult, CV_8UC3);
imgLaplacian.convertTo(imgLaplacian, CV_8UC3);
// imshow( "Laplace Filtered Image", imgLaplacian );
imshow( "New Sharped Image", imgResult );
src = imgResult; // copy back
// Create binary image from source image
Mat bw;
imshow( "Binary Image", bw);
// Perform the distance transform algorithm
//完成距离变换算法
Mat dist;
// Normalize the distance image for range = {0.0, 1.0}
// so we can visualize and threshold it
normalize(dist, dist, 0, 1., NORM_MINMAX);
imshow( "Distance Transform Image", dist);



//Now we tranfrom our new sharped source image to a grayscale and a binary one, respectively:
//灰度图像和二值图像转化
// Threshold to obtain the peaks
// This will be the markers for the foreground objects
threshold(dist, dist, .4, 1., CV_THRESH_BINARY);
// Dilate a bit the dist image
Mat kernel1 = Mat::ones(3, 3, CV_8UC1);
dilate(dist, dist, kernel1);
imshow( "Peaks", dist);
// Create the CV_8U version of the distance image
// It is needed for findContours()
Mat dist_8u;
dist. convertTo(dist_8u, CV_8U);
// Find total markers
vector<vector<Point> > contours;
// Create the marker image for the watershed algorithm
Mat markers = Mat::zeros(dist. size(), CV_32SC1);
// Draw the foreground markers
for ( size_t i = 0; i < contours.size(); i++)
drawContours(markers, contours, static_cast<int>(i), Scalar::all(static_cast<int>(i)+1), -1);
// Draw the background marker
circle(markers, Point(5,5), 3, CV_RGB(255,255,255), -1);
imshow( "Markers", markers*10000);
// Perform the watershed algorithm
watershed(src, markers);
Mat mark = Mat::zeros(markers. size(), CV_8UC1);
markers. convertTo(mark, CV_8UC1);
bitwise_not(mark, mark);
// imshow("Markers_v2", mark); // uncomment this if you want to see how the mark
// image looks like at that point
// Generate random colors
vector<Vec3b> colors;
for ( size_t i = 0; i < contours.size(); i++)
{
int b = theRNG(). uniform(0, 255);
int g = theRNG(). uniform(0, 255);
int r = theRNG(). uniform(0, 255);
colors.push_back( Vec3b(( uchar)b, ( uchar)g, ( uchar)r));
}
// Create the result image
Mat dst = Mat::zeros(markers. size(), CV_8UC3);
// Fill labeled objects with random colors
for ( int i = 0; i < markers. rows; i++)
{
for ( int j = 0; j < markers. cols; j++)
{
int index = markers. at< int>(i,j);
if (index > 0 && index <= static_cast<int>(contours.size()))
dst. at< Vec3b>(i,j) = colors[index-1];
else
dst. at< Vec3b>(i,j) = Vec3b(0,0,0);
}
}
// Visualize the final image
imshow( "Final Result", dst);
waitKey(0);
return 0;
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于分水岭算法图像分割是一种常用的图像处理技术,可以将图像分割成多个区域,每个区域内的像素具有相似的特征。在 OpenCV 中,可以使用 cv2.watershed() 函数实现基于分水岭算法图像分割。 下面是一个简单的 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) # 距离变换 dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5) ret, sure_fg = cv2.threshold(dist_transform,0.1*dist_transform.max(),255,0) # 背景区域 sure_bg = cv2.dilate(opening,kernel,iterations=3) # 不确定区域 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('image', img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 在上面的示例中,首先读取一张图像,并将其转换为灰度图像。然后使用阈值分割算法将图像二值化。接下来,进行形态学操作,以去除图像中的噪声。然后使用距离变换算法计算前景区域,并将其阈值化。接着,使用形态学操作计算背景区域。最后,使用 cv2.connectedComponents() 函数计算不确定区域,并使用标记连通区域的方法生成分水岭算法的输入标记图像。最后,应用 cv2.watershed() 函数进行图像分割,并在窗口中显示结果。 需要注意的是,分水岭算法的结果依赖于输入标记图像的质量,因此需要根据具体情况进行调整,比如阈值分割的参数、形态学操作的参数、距离变换的参数等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值