本例程比较有趣,结果呈现如下:
程序运行简单逻辑为:
运行后,程序源图片,用户用鼠标在图形上绘制2个以上的不连续区域后,点w或空格键,则系统根据用户选择进行图片分区。现模简单介绍一下程序代码
var markerMask = new Mat();
Cv2.CvtColor(srcCopy, markerMask, ColorConversionCodes.BGRA2GRAY);
var imgGray = new Mat();
Cv2.CvtColor(markerMask, imgGray, ColorConversionCodes.GRAY2BGR);
markerMask = new Mat(markerMask.Size(), markerMask.Type(), s: Scalar.All(0));
系统利用cvrColor函数,经过2次变换,有bgra图片,变换成bgr图片(依然是灰度图)
并创建了一个和markerMask同大同类型的全0矩阵。
然后根据鼠标坐标,在markerMask和源图上面绘制鼠标路径
Cv2.Line(img: markerMask, pt1: previousPoint, pt2: pt, color: Scalar.All(255), thickness: 5);
Cv2.Line(img: srcCopy, pt1: previousPoint, pt2: pt, color: Scalar.All(255), thickness: 5);
如果用户按下了r键,则恢复源图和markerMask
如果用户按下了空格键盘则在markerMask找到轮廓,代码如下:
Point[][] contours; //vector<vector<Point>> contours;
HierarchyIndex[] hierarchyIndexes; //vector<Vec4i> hierarchy;
Cv2.FindContours(
markerMask,
out contours,
out hierarchyIndexes,
mode: RetrievalModes.CComp,
method: ContourApproximationModes.ApproxSimple);
接下来利用循环把轮廓都绘制出来
var markers = new Mat(markerMask.Size(), MatType.CV_32S, s: Scalar.All(0));
var componentCount = 0;
var contourIndex = 0;
while ((contourIndex >= 0))
{
Cv2.DrawContours(
markers,
contours,
contourIndex,
color: Scalar.All(componentCount+1),
thickness: -1,
lineType: LineTypes.Link8,
hierarchy: hierarchyIndexes,
maxLevel: int.MaxValue);
componentCount++;
contourIndex = hierarchyIndexes[contourIndex].Next;
}
利用 Cv2.Watershed(src, markers);得到原图基于markers为中心的突变点。
根据突变点利用随机颜色对区域涂色
for (var i = 0; i < markers.Rows; i++)
{
for (var j = 0; j < markers.Cols; j++)
{
var idx = markers.At<int>(i, j);
if (idx == -1)
{
watershedImage.Set(i, j, new Vec3b(255, 255, 255));
}
else if (idx <= 0 || idx > componentCount)
{
watershedImage.Set(i, j, new Vec3b(0, 0, 0));
}
else
{
watershedImage.Set(i, j, colorTable[idx - 1]);
}
}
}
最后就是图片叠加和显示
watershedImage = watershedImage * 0.5 + imgGray * 0.5;
Cv2.ImShow("Watershed Transform", watershedImage);