-
watershed算法
2011-11-20 00:02:53watershed的代码,是学习的好资料啊,经典的代码的啊,要的话赶紧下啊 -
Watershed算法
2017-06-01 20:19:25先找一些资料,然后再分析和实现 参考资料: http://cmm.ensmp.fr/~beucher/wtshed....https://cn.mathworks.com/company/newsletters/articles/the-watershed-transform-strategies-for-image-segmentation.html -
watershed算法和图像分割
2017-07-06 19:02:18图像分割学习opencv是为了工程应用,只学习不应用,等于白学习。下面分析一个图像分割的例子,以加强学习。目标 学习使用cv::filter2D执行一些...学习使用cv::watershed从背景中隔离物体 代码#include <opencv2/图像分割
学习opencv是为了工程应用,只学习不应用,等于白学习。下面分析一个图像分割的例子,以加强学习。
目标
- 学习使用cv::filter2D执行一些laplacian滤波来锐化图像
- 学习使用cv::distanceTransform来获得二进制图像的导出表示,其中每个像素的值被替换为最近的背景像素的距离
- 学习使用cv::watershed从背景中隔离物体
代码
#include <opencv2/opencv.hpp> #include <iostream> using namespace std; using namespace cv; int main(int, char** argv) { // Load the image Mat src = imread(argv[1]); // Check if everything was fine if (!src.data) return -1; // Show source image imshow("Source Image", src); // Change the background from white to black, since that will help later to extract // better results during the use of Distance Transform 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; } } } // Show output image 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 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; cvtColor(src, bw, CV_BGR2GRAY); threshold(bw, bw, 40, 255, CV_THRESH_BINARY | CV_THRESH_OTSU); imshow("Binary Image", bw); // Perform the distance transform algorithm Mat dist; distanceTransform(bw, dist, CV_DIST_L2, 3); // 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); // 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; findContours(dist_8u, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); // 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;
代码说明
- 通过文件加载图像,并检查显示。
// Load the image Mat src = imread(argv[1]); // Check if everything was fine if (!src.data) return -1; // Show source image imshow("Source Image", src);
2.如果图像背景是白色的,最好转化成黑色的,在距离变换时这将有助于前景区分对象。(这个操作很生硬,因为很多时候图像都不是纯色)
// Change the background from white to black, since that will help later to extract // better results during the use of Distance Transform 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; } } } // Show output image imshow("Black Background Image", src);
3.接下来锐化图像来强化前景物体的边缘。通过使用laplacian滤波。
// 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 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 );
4.转成灰度图像和二值化。
// Create binary image from source image Mat bw; cvtColor(src, bw, CV_BGR2GRAY); threshold(bw, bw, 40, 255, CV_THRESH_BINARY | CV_THRESH_OTSU); imshow("Binary Image", bw);
5.应用Distance Tranform于二值化的图像。另外,我们通过normalize处理图像。
// Perform the distance transform algorithm Mat dist; distanceTransform(bw, dist, CV_DIST_L2, 3); // 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);
6.二值化图像然后执行腐蚀操作。
// 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);
7.从每一个小块上创建标记给watershed 算法
// 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; findContours(dist_8u, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); // 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);
8.最后,我们使用watershed算法,并且可视化它。
// 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);
-
OpenCV-Python 图像分割与Watershed算法 | 三十四
2020-01-23 19:32:08我们将学习使用分水岭算法实现基于标记的图像分割 我们将看到:cv.watershed() 理论 任何灰度图像都可以看作是一个地形表面,其中高强度表示山峰,低强度表示山谷。你开始用不同颜色的水(标签)填充每个孤立的山谷...目标
在本章中,
- 我们将学习使用分水岭算法实现基于标记的图像分割
- 我们将看到:cv.watershed()
理论
任何灰度图像都可以看作是一个地形表面,其中高强度表示山峰,低强度表示山谷。你开始用不同颜色的水(标签)填充每个孤立的山谷(局部最小值)。随着水位的上升,根据附近的山峰(坡度),来自不同山谷的水明显会开始合并,颜色也不同。为了避免这种情况,你要在水融合的地方建造屏障。你继续填满水,建造障碍,直到所有的山峰都在水下。然后你创建的屏障将返回你的分割结果。这就是Watershed背后的“思想”。你可以访问Watershed的CMM网页,了解它与一些动画的帮助。
但是这种方法会由于图像中的噪声或其他不规则性而产生过度分割的结果。因此OpenCV实现了一个基于标记的分水岭算法,你可以指定哪些是要合并的山谷点,哪些不是。这是一个交互式的图像分割。我们所做的是给我们知道的对象赋予不同的标签。用一种颜色(或强度)标记我们确定为前景或对象的区域,用另一种颜色标记我们确定为背景或非对象的区域,最后用
0
标记我们不确定的区域。这是我们的标记。然后应用分水岭算法。然后我们的标记将使用我们给出的标签进行更新,对象的边界值将为-1
。代码
下面我们将看到一个有关如何使用距离变换和分水岭来分割相互接触的对象的示例。
考虑下面的硬币图像,硬币彼此接触。即使你设置阈值,它也会彼此接触。
我们先从寻找硬币的近似估计开始。因此,我们可以使用Otsu的二值化。
import numpy as np import cv2 as cv from matplotlib import pyplot as plt img = cv.imread('coins.png') gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY) ret, thresh = cv.threshold(gray,0,255,cv.THRESH_BINARY_INV cv.THRESH_OTSU)
现在我们需要去除图像中的任何白点噪声。为此,我们可以使用形态学扩张。要去除对象中的任何小孔,我们可以使用形态学侵蚀。因此,现在我们可以确定,靠近对象中心的区域是前景,而离对象中心很远的区域是背景。我们不确定的唯一区域是硬币的边界区域。
因此,我们需要提取我们可确定为硬币的区域。侵蚀会去除边界像素。因此,无论剩余多少,我们都可以肯定它是硬币。如果物体彼此不接触,那将起作用。但是,由于它们彼此接触,因此另一个好选择是找到距离变换并应用适当的阈值。接下来,我们需要找到我们确定它们不是硬币的区域。为此,我们扩张了结果。膨胀将对象边界增加到背景。这样,由于边界区域已删除,因此我们可以确保结果中背景中的任何区域实际上都是背景。参见下图。
剩下的区域是我们不知道的区域,无论是硬币还是背景。分水岭算法应该找到它。这些区域通常位于前景和背景相遇(甚至两个不同的硬币相遇)的硬币边界附近。我们称之为边界。可以通过从
sure_bg
区域中减去sure_fg
区域来获得。# 噪声去除 kernel = np.ones((3,3),np.uint8) opening = cv.morphologyEx(thresh,cv.MORPH_OPEN,kernel, iterations = 2) # 确定背景区域 sure_bg = cv.dilate(opening,kernel,iterations=3) # 寻找前景区域 dist_transform = cv.distanceTransform(opening,cv.DIST_L2,5) ret, sure_fg = cv.threshold(dist_transform,0.7*dist_transform.max(),255,0) # 找到未知区域 sure_fg = np.uint8(sure_fg) unknown = cv.subtract(sure_bg,sure_fg)
查看结果。在阈值图像中,我们得到了一些硬币区域,我们确定它们是硬币,并且现在已分离它们。(在某些情况下,你可能只对前景分割感兴趣,而不对分离相互接触的对象感兴趣。在那种情况下,你无需使用距离变换,只需侵蚀就足够了。侵蚀只是提取确定前景区域的另一种方法。)
现在我们可以确定哪些是硬币的区域,哪些是背景。因此,我们创建了标记(它的大小与原始图像的大小相同,但具有int32数据类型),并标记其中的区域。我们肯定知道的区域(无论是前景还是背景)都标有任何正整数,但是带有不同的整数,而我们不确定的区域则保留为零。为此,我们使用cv.connectedComponents()。它用0标记图像的背景,然后其他对象用从1开始的整数标记。
但是我们知道,如果背景标记为0,则分水岭会将其视为未知区域。所以我们想用不同的整数来标记它。相反,我们将未知定义的未知区域标记为0。
# 类别标记 ret, markers = cv.connectedComponents(sure_fg) # 为所有的标记加1,保证背景是0而不是1 markers = markers 1 # 现在让所有的未知区域为0 markers[unknown==255] = 0
参见JET colormap中显示的结果。深蓝色区域显示未知区域。当然,硬币的颜色不同。剩下,肯定为背景的区域显示在较浅的蓝色,跟未知区域相比。
现在我们的标记已准备就绪。现在是最后一步的时候了,使用分水岭算法。然后标记图像将被修改。边界区域将标记为-1。
markers = cv.watershed(img,markers) img[markers == -1] = [255,0,0]
请参阅下面的结果。对某些硬币,它们接触的区域被正确地分割,而对于某些硬币,却不是。
附加资源
- CMM page on Watershed Transformation
练习
- OpenCV samples has an interactive sample on watershed segmentation, watershed.py. Run it, Enjoy it, then learn it.
欢迎关注磐创博客资源汇总站:http://docs.panchuang.net/
欢迎关注PyTorch官方中文教程站:http://pytorch.panchuang.net/
OpenCV中文官方文档:http://woshicver.com/
-
图像分割算法_OpenCV-Python 图像分割与Watershed算法 | 三十四
2020-12-18 02:42:12目标在本章中,我们将学习使用分水岭算法实现基于标记的图像分割我们将看到:cv.watershed()理论任何灰度图像都可以看作是一个地形表面,其中高强度表示山峰,低强度表示山谷。你开始用不同颜色的水(标签)填充每个...目标
在本章中,
- 我们将学习使用分水岭算法实现基于标记的图像分割
- 我们将看到:cv.watershed()
理论
任何灰度图像都可以看作是一个地形表面,其中高强度表示山峰,低强度表示山谷。你开始用不同颜色的水(标签)填充每个孤立的山谷(局部最小值)。随着水位的上升,根据附近的山峰(坡度),来自不同山谷的水明显会开始合并,颜色也不同。为了避免这种情况,你要在水融合的地方建造屏障。你继续填满水,建造障碍,直到所有的山峰都在水下。然后你创建的屏障将返回你的分割结果。这就是Watershed背后的“思想”。你可以访问Watershed的CMM网页,了解它与一些动画的帮助。
但是这种方法会由于图像中的噪声或其他不规则性而产生过度分割的结果。因此OpenCV实现了一个基于标记的分水岭算法,你可以指定哪些是要合并的山谷点,哪些不是。这是一个交互式的图像分割。我们所做的是给我们知道的对象赋予不同的标签。用一种颜色(或强度)标记我们确定为前景或对象的区域,用另一种颜色标记我们确定为背景或非对象的区域,最后用0标记我们不确定的区域。这是我们的标记。然后应用分水岭算法。然后我们的标记将使用我们给出的标签进行更新,对象的边界值将为-1。
代码
下面我们将看到一个有关如何使用距离变换和分水岭来分割相互接触的对象的示例。
考虑下面的硬币图像,硬币彼此接触。即使你设置阈值,它也会彼此接触。
我们先从寻找硬币的近似估计开始。因此,我们可以使用Otsu的二值化。
import numpy as npimport cv2 as cvfrom matplotlib import pyplot as pltimg = cv.imread('coins.png')gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)ret, thresh = cv.threshold(gray,0,255,cv.THRESH_BINARY_INV+cv.THRESH_OTSU)
现在我们需要去除图像中的任何白点噪声。为此,我们可以使用形态学扩张。要去除对象中的任何小孔,我们可以使用形态学侵蚀。因此,现在我们可以确定,靠近对象中心的区域是前景,而离对象中心很远的区域是背景。我们不确定的唯一区域是硬币的边界区域。
因此,我们需要提取我们可确定为硬币的区域。侵蚀会去除边界像素。因此,无论剩余多少,我们都可以肯定它是硬币。如果物体彼此不接触,那将起作用。但是,由于它们彼此接触,因此另一个好选择是找到距离变换并应用适当的阈值。接下来,我们需要找到我们确定它们不是硬币的区域。为此,我们扩张了结果。膨胀将对象边界增加到背景。这样,由于边界区域已删除,因此我们可以确保结果中背景中的任何区域实际上都是背景。参见下图。
剩下的区域是我们不知道的区域,无论是硬币还是背景。分水岭算法应该找到它。这些区域通常位于前景和背景相遇(甚至两个不同的硬币相遇)的硬币边界附近。我们称之为边界。可以通过从sure_bg区域中减去sure_fg区域来获得。
# 噪声去除kernel = np.ones((3,3),np.uint8)opening = cv.morphologyEx(thresh,cv.MORPH_OPEN,kernel, iterations = 2)# 确定背景区域sure_bg = cv.dilate(opening,kernel,iterations=3)# 寻找前景区域dist_transform = cv.distanceTransform(opening,cv.DIST_L2,5)ret, sure_fg = cv.threshold(dist_transform,0.7*dist_transform.max(),255,0)# 找到未知区域sure_fg = np.uint8(sure_fg)unknown = cv.subtract(sure_bg,sure_fg)
查看结果。在阈值图像中,我们得到了一些硬币区域,我们确定它们是硬币,并且现在已分离它们。(在某些情况下,你可能只对前景分割感兴趣,而不对分离相互接触的对象感兴趣。在那种情况下,你无需使用距离变换,只需侵蚀就足够了。侵蚀只是提取确定前景区域的另一种方法。)
现在我们可以确定哪些是硬币的区域,哪些是背景。因此,我们创建了标记(它的大小与原始图像的大小相同,但具有int32数据类型),并标记其中的区域。我们肯定知道的区域(无论是前景还是背景)都标有任何正整数,但是带有不同的整数,而我们不确定的区域则保留为零。为此,我们使用cv.connectedComponents()。它用0标记图像的背景,然后其他对象用从1开始的整数标记。
但是我们知道,如果背景标记为0,则分水岭会将其视为未知区域。所以我们想用不同的整数来标记它。相反,我们将未知定义的未知区域标记为0。
# 类别标记ret, markers = cv.connectedComponents(sure_fg)# 为所有的标记加1,保证背景是0而不是1markers = markers+1# 现在让所有的未知区域为0markers[unknown==255] = 0
参见JET colormap中显示的结果。深蓝色区域显示未知区域。当然,硬币的颜色不同。剩下,肯定为背景的区域显示在较浅的蓝色,跟未知区域相比。
现在我们的标记已准备就绪。现在是最后一步的时候了,使用分水岭算法。然后标记图像将被修改。边界区域将标记为-1。
markers = cv.watershed(img,markers) img[markers == -1] = [255,0,0]
请参阅下面的结果。对某些硬币,它们接触的区域被正确地分割,而对于某些硬币,却不是。
附加资源
- CMM page on http://cmm.ensmp.fr/~beucher/wtshed.html
练习
- OpenCV samples has an interactive sample on watershed segmentation, watershed.py. Run it, Enjoy it, then learn it.
-
【图像处理】图像分割与Watershed算法
2020-06-20 16:48:21marke) cv.waitKey(0) markers = cv.watershed(img,markers) #Watershed算法 第一个参数是图像,第二个参数是标记图 #会根据markers传入的轮廓作为种子(也就是所谓的注水点), #对图像上其他的像素点根据分水岭... -
OpenCV系列之图像分割与Watershed算法 | 三十四
2019-12-19 13:28:30目标在本章中,我们将学习使用分水岭算法实现基于标记的图像分割我们将看到:cv.watershed()理论任何灰度图像都可以看作是一个地形表面,其中高强度... -
Opencv4 -Python官方教程学习笔记27---图像分割与Watershed算法
2020-07-19 14:56:07我们将学习使用分水岭算法实现基于标记的图像分割 - 我们将看到:cv.watershed() 理论 任何灰度图像都可以看作是一个地形表面,其中高强度表示山峰,低强度表示山谷。你开始用不同颜色的水(标签)填充每个孤立的山谷... -
【转载】OpenCV-Python系列之图像分割与Watershed算法(四十二)
2020-10-13 09:50:14目前有很多图像分割方法,其中分水岭算法是一种基于区域的图像分割算法,分水岭算法因实现方便,已经在医疗图像,模式识别等领域得到了广泛的应用。 传统分水岭算法基本原理 分水岭比较经典的计算方法是L.Vincent于... -
watershed分水岭算法
2017-09-19 16:17:46所谓分水岭算法有好多种实现算法,拓扑学,形态学,浸水模拟和降水模拟等方式。要搞懂就不容易了。Watershed Algorithm(分水岭算法),顾名思义,就是根据分水岭的构成来考虑图像的分割。 -
watershed分水岭算法的源代码
2009-11-15 11:52:32watershed分水岭算法的源代码,一个很实用的用于图像分割的算法 -
Watershed分水岭分割算法
2013-03-22 11:07:41Watershed分水岭分割算法,学习一下吧哈哈哈 -
OpenCV学习三十四:watershed 分水岭算法
2018-10-08 11:39:401. watershed void watershed( InputArray image, InputOutputArray markers ); 第一个参数 image,必须是一个8bit 3通道彩色图像矩阵序列,第一个参数没什么要说的。 关键是第二个参数 markers:在执行分水岭... -
基于边缘的图像分割——分水岭算法(watershed)算法分析(附opencv源码分析)
2017-04-21 15:31:04最近需要做一个图像分割的程序,查了opencv的源代码,发现opencv里实现的图像分割一共有两个方法,watershed和mean-shift算法。这两个算法的具体实现都在segmentation.cpp文件内。 watershed(分水岭算法)方法是一... -
otsu算法_OpenCV cv::watershed 分水岭算法论文解读以及numpy实现
2020-11-27 05:24:04根据官方文档The function implements one of the variants of watershed, non-parametric marker-based segmentation algorithm, described in [161] .[161] Fernand Meyer. Color image segmentation. In Image ... -
opencv 分水岭算法watershed
2017-05-26 14:21:22opencv watershed demo: http://download.csdn.net/detail/keen_zuxwang/9852585 分水岭算法 1、一种基于拓扑理论的数学形态学的图像分割方法。分水岭算法容易导致图像的过度分割。opencv中,使用预定义的一组... -
watershed分水岭算法的matlab例子详解
2014-11-24 21:45:14今天本来想试试mser算法的,结果没看懂。就先看看类似的fen'shui'l -
matlab之watershed分水岭分割算法
2017-02-22 14:34:04Separating touching objects in an image is one of the more difficult image processing operations. The watershed transform is often applied to this problem. The watershed transform finds "catchment bas
-
MySQL 查询与高级查询(多表、嵌套和正则表达式)
-
Nginx 多进程连接请求/事件分发流程分析
-
linux基础入门和项目实战部署系列课程
-
使用vue搭建微信H5公众号项目
-
C语言 const的使用
-
聊聊storagetapper的pipe
-
清华大学历年考研复试机试真题 - 1454反序数
-
009_连通页面组件
-
MySQL 数据库权限管理(用户高级管理和精确访问控制)
-
常见数据分析方法
-
【Python-随到随学】 FLask第一周
-
LVS + Keepalived 实现 MySQL 负载均衡与高可用
-
C语言零基础入门(详细讲解)
-
MySQL 管理利器 mysql-utilities
-
云开发后台+微信扫码点餐小程序+cms网页管理后台 含后厨端和用户端
-
AQS
-
PPT大神之路高清教程
-
基于SSM实现的房屋租赁系统【附源码】(毕设)
-
永久改变UG8.0背景颜色方法.txt
-
MySQL 高可用(DRBD + heartbeat)