一、图像分割

图像分割概述 【详情请点击】

图像分割(Image Segmentation)是图像处理最重要的处理手段之一
图像分割的目标是将图像中像素根据一定的规则分为若干(N)个cluster集合,每个集合包含一类像素。
根据算法分为监督学习方法和无监督学习方法,图像分割的算法多数都是无监督学习方法 - KMeans

二、距离变换与分水岭

OpenCV—Python 分水岭算法图像分割

距离变换常见算法有两种

  • 不断膨胀/ 腐蚀得到
  • 基于倒角距离

分水岭变换常见的算法

  • 基于浸泡理论实现

步骤

  1. 将白色背景变成黑色-目的是为后面的变换做准备
  2. 使用filter2D与拉普拉斯算子实现图像对比度提高,sharp(锐化)
  3. 转为二值图像通过threshold
  4. 距离变换
  5. 对距离变换结果进行归一化到[0~1]之间
  6. 使用阈值,再次二值化,得到标记
  7. 腐蚀得到每个Peak - erode
  8. 发现轮廓 – findContours
  9. 绘制轮廓- drawContours
  10. 分水岭变换 watershed
  11. 对每个分割区域着色输出结果

头文件 quick_opencv.h:声明类与公共函数

#pragma once
#include <opencv2\opencv.hpp>
using namespace cv;

class QuickDemo {
public:
	...
	void Moments_Demo(Mat& image1);

};

主函数调用该类的公共成员函数

#include <opencv2\opencv.hpp>
#include <quick_opencv.h>
#include <iostream>
using namespace cv;


int main(int argc, char** argv) {
	Mat src = imread("D:\\Desktop\\maomao.png");
	if (src.empty()) {
		printf("Could not load images...\n");
		return -1;
	}
	namedWindow("input", WINDOW_NORMAL);
	imshow("input", src);

	QuickDemo qk;
	qk.Moments_Demo(src);
	waitKey(0);
	destroyAllWindows();
	return 0;
}

三、演示

源文件 quick_demo.cpp:实现类与公共函数

void QuickDemo::Image_segmentation_Demo(Mat& image) {
	for (int row = 0; row < image.rows; row++) {
		for (int col = 0; col < image.cols; col++) {
			if (image.at<Vec3b>(row, col) == Vec3b(255, 255, 255)) {
				image.at<Vec3b>(row, col)[0] = 0;
				image.at<Vec3b>(row, col)[1] = 0;
				image.at<Vec3b>(row, col)[2] = 0;
			}
		}
	}
	imshow("image", image);
	
	// 使用掩码的方式替换颜色:python:a = np.where(a=255,0)
	//Mat mask_;
	//inRange(image, Scalar(255, 255, 255), Scalar(255, 255, 255), mask);
	//image.setTo(Scalar(0, 0, 0), mask_);


	Mat kernel_ = (Mat_<float>(3, 3) << 1, 1, 1, 1, -8, 1, 1, 1, 1);
	Mat ImgLaplance;
	Mat sharp = image;
	filter2D(sharp, ImgLaplance, CV_32F, kernel_, Point(-1, -1), 0);
	cout << "&sharp" << &sharp << endl;
	cout << "&image" << &image << endl;
	image.convertTo(sharp, CV_32F);
	Mat ImgResult = sharp - ImgLaplance;

	ImgResult.convertTo(ImgResult, CV_8UC3);
	ImgLaplance.convertTo(ImgLaplance, CV_8UC3);
	imshow("ImgResult", ImgResult);
	imshow("ImgLaplance", ImgLaplance);


	Mat binImg;
	image = ImgResult;                        // 指向锐化后的图像
	cvtColor(image, binImg, COLOR_BGR2GRAY);
	threshold(binImg, binImg, 40, 255, THRESH_BINARY | THRESH_OTSU);
	imshow("binImg", binImg);

	Mat distImg;
	distanceTransform(binImg, distImg, DIST_L2, 5);
	normalize(distImg, distImg, 0, 1, NORM_MINMAX);
	imshow("normalize", distImg);


	threshold(distImg, distImg, 0.4, 1, THRESH_BINARY);
	imshow("distance_threshold", distImg);
	
	// 查看二值化后的效果,觉得没必要做这一步了
	Mat kernel2_ = Mat::ones(5, 5, CV_8UC1);
	erode(distImg, distImg, kernel2_);
	imshow("peaks", distImg);

	// 轮廓查找,并绘制轮廓
	Mat dist_u8;
	distImg.convertTo(dist_u8, CV_8U);
	vector<vector<Point>> contours;
	findContours(dist_u8, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
	if (contours.size() == 0) {
		cout << "未找到轮廓" << endl;
		return;
	}


	Mat marks = Mat::zeros(distImg.size(), CV_32SC1);
	for (size_t i = 0; i < contours.size(); i++) {
		drawContours(marks, contours, static_cast<int>(i), Scalar::all(static_cast<uchar>(i + 1)), -1);
	}
	circle(marks, Point(5, 5), 3, Scalar(255), -1);
	//imshow("mark_dist", marks * 1000); //报错


	watershed(image, marks);
	Mat mark_dist = Mat::zeros(marks.size(), CV_8UC1);
	marks.convertTo(mark_dist, CV_8UC1);
	bitwise_not(mark_dist, mark_dist);
	imshow("watershed", mark_dist);


	// generator random color
	RNG rng(12335);
	vector<Vec3b> colors;
	for (size_t i = 0; i < contours.size(); i++){
		uchar b = rng.uniform(0, 255);
		uchar g = rng.uniform(0, 255);
		uchar r = rng.uniform(0, 255);
		colors.push_back(Vec3b(b, g, r));
	}

	//着色
	Mat drawImg = Mat::zeros(marks.size(), CV_8UC3);
	for (int row = 0; row < marks.rows; row++) {
		for (int col = 0; col < marks.cols; col++) {
			uchar index = marks.at<int>(row, col);
			if (index > 0 && index <= static_cast<int>(contours.size())) {
				drawImg.at<Vec3b>(row, col) = colors[index - 1];
			}
			else {
				drawImg.at<Vec3b>(row, col) = Vec3b(0, 0, 0);
			}
		}
	}
	imshow("dst", drawImg);
}

效果图(展示关键步骤效果):
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐