OpenCV图像处理基础


01. 加载、修改、保存图像

(1)加载图像

(2)显示图像

(3)修改图像

(4)保存图像

(5)演示程序

#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>

using namespace std;
using namespace cv;

int main(int argc, char** argv) {
	Mat src = imread("C:/images/leaf.jpg");
	if (src.empty()) {
		return -1;
	}
	namedWindow("input", CV_WINDOW_AUTOSIZE);
	imshow("input", src);
	
	Mat dst;
	cvtColor(src, dst, CV_BGR2GRAY);
	namedWindow("gray", CV_WINDOW_AUTOSIZE);
	imshow("gray", dst);

	imwrite("C:/images/leaf-gray.jpg", dst);

	waitKey(0);
	return 0;
}

02 矩阵的掩膜操作

(1)获取图像像素指针

(2)像素范围处理aturates_cast<uchar>

(3)函数调用filter2D功能

 

(4)演示程序

#include<opencv2/opencv.hpp>

using namespace cv;

int main()
{
	Mat src, dst;
	src = imread("C:/Users/52051/Desktop/images/cat.jpg");

	int row = src.rows;
	int col = src.cols * src.channels();
	int offset = src.channels();
	dst = Mat::zeros(src.size(), src.type());

	for (int i = 1; i < row - 1; i++)
	{
		for (int j = 1; j <= col - 1; j++)
		{
			uchar* pre = src.ptr<uchar>(i - 1);
			uchar* cur = src.ptr<uchar>(i);
			uchar * ne = src.ptr<uchar>(i + 1);
			uchar* temp = dst.ptr<uchar>(i);
			temp[j] = saturate_cast<uchar>(cur[j] * 5 - (cur[j - offset] + cur[j + offset] + pre[j] + ne[j]));
		}
	}

	namedWindow("input image", CV_WINDOW_AUTOSIZE);
	imshow("input image", src);
	namedWindow("output image", CV_WINDOW_AUTOSIZE);
	imshow("output image", dst);
	waitKey(0);
	return 0;
}

03. Mat对象

(1)Mat对象构造函数与常用方法

(2)Mat对象的创建

(3)定义小数组

(4)演示程序

#include<opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
	Mat src = imread("C:\\Users\\52051\\Desktop\\images\\people.jpg");
	if (src.empty()) {
		cout << "failed" << endl;
		return -1;
	}

	namedWindow("input", CV_WINDOW_AUTOSIZE);
	imshow("input", src);

	Mat dst;
	dst = Mat(src.size(), src.type());
	dst = Scalar(0, 0, 255);
	namedWindow("output", CV_WINDOW_AUTOSIZE);
	imshow("output", dst);

	//dst = src.clone();
	src.copyTo(dst);
	namedWindow("copy", CV_WINDOW_AUTOSIZE);
	imshow("copy", dst);
	
	int cols = src.cols;
	int rows = src.rows;
	cout << cols << " " << rows << endl;
	
	Mat m1;
	m1.create(src.size(), src.type());
	m1 = Scalar(0, 0, 255);
	Mat kernel = (Mat_<float>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
	Mat csrc;
	filter2D(src, csrc, -1, kernel);
	namedWindow("kernel", CV_WINDOW_AUTOSIZE);
	imshow("kernel", csrc);
	
	Mat m2 = Mat::eye(2, 2, CV_8UC1);
	cout << m2 << endl;

	waitKey(0);
	return 0;
}

04. 图像操作

(1)读写操作

(2)读写像素

(3)修改像素值

(4)Vec3b与Vec3F

(5)演示程序

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
	Mat src = imread("C:\\Users\\Demo\\Desktop\\images\\people.jpg");
	if (src.empty())
	{
		puts("failed");
		return -1;
	}

	imshow("input", src);

	Mat gray_src;
	cvtColor(src, gray_src, CV_BGR2GRAY);
	imshow("output gray1", gray_src);

	int rows = src.rows;
	int cols = src.cols;
	// 单通道
	for (int i = 0; i < rows; i++)
		for (int j = 0; j < cols; j++)
		{
			int gray = gray_src.at<uchar>(i, j);
			gray_src.at<uchar>(i, j) = 255 - gray;
		} 
	imshow("output gray2", gray_src);

	// 三通道
	Mat dst;
	dst.create(src.size(), src.type());
	for (int i = 0; i < rows; i ++)
		for (int j = 0; j < cols; j++)
		{
			if (src.channels() == 1)
			{
				int gray = gray_src.at<uchar>(i, j);
				gray_src.at<uchar>(i, j) = 255 - gray;
			}
			else if (src.channels() == 3)
			{
				int b = src.at<Vec3b>(i, j)[0];
				int g = src.at<Vec3b>(i, j)[1];
				int r = src.at<Vec3b>(i, j)[2];

				dst.at<Vec3b>(i, j)[0] = ~b;
				dst.at<Vec3b>(i, j)[1] = ~g;
				dst.at<Vec3b>(i, j)[2] = ~r;
			}
		}
	imshow("output gray3", dst);
	// 利用函数
	bitwise_not(src, dst);
	imshow("input gray4", dst);

	// 空白图像
	Mat img;
	img.create(src.size(), src.type());
	img = Scalar(0, 0, 0);
	imshow("White Image", img);

	waitKey(0);
	return 0;
}

05. 图像混合

(1)相关API (addWeighted)

(2)演示程序

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
	Mat src1 = imread("C:\\Users\\Demo\\Desktop\\images\\people.jpg");
	Mat src2 = imread("C:\\Users\\Demo\\Desktop\\images\\earth.jpg");
	if (src1.empty() || src2.empty())
	{
		puts("failed");
		return -1;
	}

	double alpha = 0.5;
	cout << src1.rows << " " << src2.rows << " " << src1.cols << " " << src2.rows << endl;
	if (src1.rows != src2.rows || src1.cols != src2.cols || src1.type() != src2.type())
	{
		return -1;
	}
	Mat dst;
	addWeighted(src1, alpha, src2, 1 - alpha, 0, dst);
	//add(src1, src2, dst, Mat());
	//multiply(src1, src2, dst, 1.0);
	imshow("blend image", dst);

	waitKey(0);
	return 0;
}

06. 调整图像亮度和对比度

(1)理论

(2)重要API

(3)演示程序

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
	Mat src, dst;
	src = imread("C:\\Users\\Demo\\Desktop\\images\\people.jpg");
	if (src.empty()) 
	{
		return -1;
	}
	imshow("input", src);

	dst = Mat::zeros(src.size(), src.type());
	float alpha = 1.5; // 对比度
	float beta = 100; // 亮度
	for (int i = 0; i < src.rows; i++)
		for (int j = 0; j < src.cols; j++){
			if (src.channels() == 3) {
				float b = src.at<Vec3b>(i, j)[0];
				float g = src.at<Vec3b>(i, j)[1];
				float r = src.at<Vec3b>(i, j)[2];

				dst.at<Vec3b>(i, j)[0] = saturate_cast<uchar>(b * alpha + beta);
				dst.at<Vec3b>(i, j)[1] = saturate_cast<uchar>(g * alpha + beta);
				dst.at<Vec3b>(i, j)[2] = saturate_cast<uchar>(r * alpha + beta);
			}
			else if (src.channels() == 1) {
				float v = src.at<uchar>(i, j);
				dst.at<uchar>(i, j) = saturate_cast<uchar>(v * alpha + beta);
			}
		}
	imshow("output", dst);

	waitKey(0);
	return 0;
}

07. 绘制图像与文字

(1)使用cv::Point与cv::Scalar

(2)绘制线、矩形、园、椭圆等基本几何形状

(3)填充矩形

(4)随机数生成cv::RNG

(5)绘制添加文字

(6)演示程序

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

Mat src;

void MyLines1() {
	Point p1 = Point(30, 30);
	Point p2;
	p2.x = 200;
	p2.y = 200;
	Scalar color = Scalar(255, 0, 0);
	line(src, p1, p2, color, 2, LINE_4);
}
void MyLines2() {
	Point p1 = Point(40, 40);
	Point p2;
	p2.x = 200;
	p2.y = 200;
	Scalar color = Scalar(255, 0, 0);
	line(src, p1, p2, color, 2, LINE_8);
}
void MyLines3() {
	Point p1 = Point(50, 50);
	Point p2;
	p2.x = 200;
	p2.y = 200;
	Scalar color = Scalar(255, 0, 0);
	line(src, p1, p2, color, 2, LINE_AA);
}

void MyRectangle() {
	Rect rect = Rect(200, 100, 300, 300);
	Scalar color = Scalar(255, 0, 0);
	rectangle(src, rect, color, 2, LINE_4);
}

void  MyEllipse() {
	Scalar color = Scalar(0, 255, 0);
	ellipse(src, Point(src.rows / 2, src.cols / 2), Size(src.cols / 4, src.rows / 8), 90, 0, 360, color, 2, LINE_8);
}

void MyCircle() {
	Scalar color = Scalar(0, 255, 255);
	Point center = Point(src.rows / 2, src.cols / 2);
	circle(src, center, 50, color, 2, 8);
}

void MyPolygon() {
	Point pts[1][5];
	pts[0][0] = Point(100, 100);
	pts[0][1] = Point(100, 200);
	pts[0][2] = Point(200, 200);
	pts[0][3] = Point(200, 100);
	pts[0][4] = Point(100, 100);
	const Point* ppts[] = { pts[0] };
	int npt[] = { 5 };
	Scalar color = Scalar(255, 12, 255);
	fillPoly(src, ppts, npt, 1, color, 8);

}

void RandomLineDemo() {
	RNG rng;
	Point p1, p2;
	Mat bg = Mat::zeros(src.size(), src.type());
	for (int i = 0; i < 100000; i++)
	{
		p1.x = rng.uniform(0, src.rows);
		p2.x = rng.uniform(0, src.rows);
		p1.y = rng.uniform(0, src.cols);
		p2.y = rng.uniform(0, src.cols);
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		if (waitKey(50) > 0) {
			break;
		}
		line(bg, p1, p2, color, 1, 8);
		imshow("random", bg);
	}
}

int main()
{
	src = imread("C:\\Users\\Demo\\Desktop\\images\\people.jpg");
	if (src.empty()) {
		return -1;
	}

	MyLines1();
	MyLines2();
	MyLines3();
	MyRectangle();
	MyEllipse();
	MyCircle();
	MyPolygon();
	putText(src, "HelloOpenCV!", Point(30, 30), CV_FONT_HERSHEY_COMPLEX,1.0, Scalar(12, 255, 200), 3, 8);
	
	
	imshow("circle", src);
	RandomLineDemo();

	waitKey(0);
	return 0;
}

08. 模糊图像一

(1)模糊原理

(2)相关API

(3)演示程序

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;


int main()
{
	Mat src = imread("C:\\Users\\Demo\\Desktop\\images\\people.jpg");
	if (src.empty()) {
		return -1;
	}
	imshow("input", src);

	Mat dst;
	blur(src, dst, Size(3, 3), Point(-1, -1));
	imshow("blur", dst);

	Mat gblur;
	GaussianBlur(src, gblur, Size(5, 5), 11, 11);
	imshow("GaussianBlur", gblur);

	waitKey(0);
	return 0;
}

09. 模糊图像二

(1)中值滤波

(2)双边滤波

(3)相关API

(4)演示程序

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;


int main()
{
	Mat src = imread("C:/images/blur.jpg");
	if (src.empty()) {
		return -1;
	}
	imshow("input", src);

	Mat dst;
	//medianBlur(src, dst, 3);
	bilateralFilter(src, dst, 15, 70, 3);
	imshow("BiBlur", dst);

	Mat rsImg;
	Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
	filter2D(dst, rsImg, -1, kernel);
	imshow("rsImg", rsImg);

	waitKey(0);
	return 0;
}

10. 膨胀与腐蚀

(1)形态学操作

(2)形态学操作——膨胀

(3)形态学操作——腐蚀

(4)相关API

(5)演示程序

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

Mat src = imread("C:/images/cat.jpg");
Mat dst;
int element_size = 0;
int max_size = 13;

void callback_demo(int, void*) {
	int s = element_size * 2 + 1;
	Mat structureElement = getStructuringElement(MORPH_RECT, Size(s, s), Point(-1, -1));
	//dilate(src, dst, structureElement, Point(-1, -1), 1); // 膨胀
	erode(src, dst, structureElement); // 腐蚀
	imshow("output", dst);
}


int main()
{
	if (src.empty()) {
		return -1;
	}
	imshow("input", src);

	namedWindow("output", CV_WINDOW_AUTOSIZE);
	createTrackbar("Element Size:", "output", &element_size, max_size, callback_demo);
	callback_demo(0, 0);

	waitKey(0);
	return 0;
}

11. 形态学操作

(1)开操作——open

(2)闭操作——close

(3)形态学梯度——Morphological Gradient

(4)顶帽——top hat

(5)黑帽——black hat

(6)演示程序

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
	Mat src = imread("C:/images/origin.png");
	if (src.empty()) {
		return -1;
	}
	imshow("input", src);

	Mat kernel, dst;
	kernel = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
	morphologyEx(src, dst, CV_MOP_OPEN, kernel); // open 操作
	imshow("open", dst);

	kernel = getStructuringElement(MORPH_RECT, Size(11, 11), Point(-1, -1));
	morphologyEx(src, dst, CV_MOP_CLOSE, kernel); // close 操作
	imshow("close", dst);

	//morphologyEx(src, dst, CV_MOP_GRADIENT, kernel); // GRADIENT 操作
	//morphologyEx(src, dst, CV_MOP_TOPHAT, kernel); // 顶帽 操作
	//morphologyEx(src, dst, CV_MOP_BLACKHAT, kernel); // 黑帽 操作

	waitKey(0);
	return 0;
}

12. 形态学操作应用——提取水平线与垂直线

(1)原理方法

(2)结构元素

(3)提取步骤

(4)程序演示

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
	Mat src = imread("C:/images/abcd.png");
	if (src.empty()) {
		return -1;
	}
	imshow("input", src);

	// 转换为灰度图像
	Mat gray_src;
	cvtColor(src, gray_src, CV_BGR2GRAY);
	imshow("gray image", gray_src);

	// 转换为二值图像
	Mat binImg;
	adaptiveThreshold(~gray_src, binImg, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, -2);
	imshow("binary image", binImg);

	// 结构元素
	Mat hline = getStructuringElement(MORPH_RECT, Size(src.cols / 16, 1), Point(-1, -1));
	Mat vline = getStructuringElement(MORPH_RECT, Size(1, src.rows / 16), Point(-1, -1));
	Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1)); // 可以对验证码图片去除干扰


	// open 操作
	Mat dst, temp;
	//erode(binImg, temp, hline);
	//dilate(temp, dst, hline);
	//erode(binImg, temp, hline);
	//dilate(temp, dst, hline);
	//morphologyEx(binImg, dst, CV_MOP_OPEN, vline);
	//morphologyEx(binImg, dst, CV_MOP_OPEN, hline);
	//blur(dst, dst, Size(3, 3), Point(-1, -1)); // 更酷

	morphologyEx(binImg, dst, CV_MOP_OPEN, kernel);

	imshow("output", dst); 

	waitKey(0);
	return 0;
}

13. 图像金字塔——上采样与降采样

(1)图像金字塔概念

(2)高斯金字塔

(3)高斯不同

(4)相关API

(5)演示程序

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
	Mat src = imread("C:/images/cat.jpg");
	if (src.empty()) {
		return -1;
	}
	imshow("input", src);

	 // 上采样
	Mat dst;
	pyrUp(src, dst, Size(src.cols * 2, src.rows * 2));
	imshow("up", dst);

	// 降采样
	pyrDown(src, dst, Size(src.cols / 2, src.rows / 2));
	imshow("down", dst);

	// 高斯不同 DOG
	Mat gray_src, g1, g2, dogImg;
	cvtColor(src, gray_src, CV_BGR2GRAY);
	GaussianBlur(gray_src, g1, Size(3, 3), 0, 0);
	GaussianBlur(g1, g2, Size(3, 3), 0, 0);
	subtract(g1, g2, dogImg, Mat());
	imshow("DOG", dogImg);
	normalize(dogImg, dogImg, 255, 0, NORM_MINMAX);
	imshow("DOG Normalize", dogImg);

	waitKey(0);
	return 0;
}

14. 基本阈值操作

(1)图像阈值(threshold)

(2)阈值类型一阈值二值化(threshold binary)

(3)阈值类型一阈值反二值化(threshold binary Inverted)

(4)阈值类型一截断 (truncate)

(5)阈值类型一阈值取零 (threshold to zero)

(6)阈值类型一阈值反取零 (threshold to zero inverted)

(7)汇总

(8)演示程序

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

Mat src, gray_src, dst;
int threshold_value = 127;
int threshold_max = 255;

void Threshold_Demo(int, void *)
{
	cvtColor(src, gray_src, CV_BGR2GRAY);
	threshold(gray_src, dst, threshold_value, threshold_max, THRESH_BINARY);
	imshow("output", dst);
}

int main()
{
	src = imread("C:/images/cat.jpg");
	if (src.empty()) {
		return -1;
	}
	
	imshow("input", src);
	namedWindow("output", CV_WINDOW_AUTOSIZE);

	createTrackbar("Threshold Value:", "output", &threshold_value, threshold_max, Threshold_Demo);
	Threshold_Demo(0, 0);

	waitKey(0);
	return 0;
}

15. 自定义线性滤波

(1)卷机概念

(2)卷积是如何工作的

(3)常见算子

(4)自定义卷积模糊

(5)演示程序

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
	Mat src = imread("C:/images/cat.jpg");
	if (src.empty()) {
		return -1;
	}
	imshow("input", src);
	
	// robert 算子
	Mat robert_x = (Mat_<char>(2, 2) << 1, 0, 0, -1);
	Mat robert_y = (Mat_<char>(2, 2) << 0, 1, -1, 0);
	Mat dst;
	filter2D(src, dst, -1, robert_x, Point(-1, -1), 0);
	imshow("robert x", dst);
	filter2D(src, dst, -1, robert_y, Point(-1, -1), 0);
	imshow("robert y", dst);

	// sobel 算子
	Mat sobel_x = (Mat_<char>(3, 3) << -1, 0, 1, -2, 0, 2, -1, 0, 1);
	Mat sobel_y = (Mat_<char>(3, 3) << -1, -2, -1, 0, 0, 0, 1, 2, 1);
	filter2D(src, dst, -1, sobel_x, Point(-1, -1), 0);
	imshow("sobel x", dst);
	filter2D(src, dst, -1, sobel_y, Point(-1, -1), 0);
	imshow("sobel y", dst);

	// laplace 算子
	Mat laplace = (Mat_<char>(3, 3) << 0, -1, 0, -1, 4, -1, 0, -1, 0);
	filter2D(src, dst, -1, laplace, Point(-1, -1), 0);
	imshow("laplace", dst);

	waitKey(0);
	return 0;
}
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
	Mat src = imread("C:/images/cat.jpg");
	if (src.empty()) {
		return -1;
	}
	imshow("input", src);
	// 自定义模糊
	int c = 0;
	int index = 0;
	int ksize = 3;
	Mat dst;
	while (true) {
		c = waitKey(500);
		if (c == 27) { // ESC
			break;
		}
		ksize = 4 + (index % 5) * 2 + 1;
		Mat kernel = Mat::ones(ksize, ksize, CV_32F) / (float)(ksize * ksize);
		filter2D(src, dst, -1, kernel, Point(-1, -1));
		index++;
		imshow("output", dst);
	}

	waitKey(0);
	return 0;
}

16. 处理边缘

(1)卷积边缘问题

(2)处理边缘

(3)相关API

(4)演示程序

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
	Mat src = imread("C:/images/cat.jpg");
	if (src.empty()) {
		return -1;
	}
	imshow("input", src);
	
	Mat dst;
	int c = 0;
	int borderType = BORDER_DEFAULT;
	RNG rng;
	int top = int(0.05 * src.rows);
	int bottom = int(0.05 * src.rows);
	int left = int(0.05 * src.cols);
	int right = int(0.05 * src.cols);
	while (true) {
		c = waitKey(500);
		if (c == 27) { // ESC
			break;
		}
		else if (c == 'r') {
			borderType = BORDER_WRAP;
		}
		else if (c == 'c')
		{
			borderType = BORDER_CONSTANT;
		}
		else
		{
			borderType = BORDER_DEFAULT;
		}
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		copyMakeBorder(src, dst, top, bottom, left, right, borderType, color);
		imshow("output", dst);
	}

	waitKey(0);
	return 0;
}

17. Sobel算子

(1)卷积的应用——图像边缘提取

(2)Sobel算子

(3)相关API

(4)其他API

(5)演示程序

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
	Mat src = imread("C:/images/gm.jpg");
	if (src.empty()) {
		return -1;
	}
	imshow("input", src);
	
	Mat gblur, gray_src, dst;
	// 第一步:高斯平滑
	GaussianBlur(src, gblur, Size(3, 3), 0);
	// 第二步:灰度图像
	cvtColor(gblur, gray_src, CV_BGR2GRAY);
	// x y 梯度
	Mat xgrade, ygrade;

	Scharr(gray_src, xgrade, -1, 1, 0);
	Scharr(gray_src, ygrade, -1, 0, 1);
	imshow("Scharr-x", xgrade);
	imshow("Scharr-y", ygrade);

	/*Sobel(gray_src, xgrade, CV_16S, 1, 0);
	Sobel(gray_src, ygrade, CV_16S, 0, 1);
	convertScaleAbs(xgrade, xgrade);
	convertScaleAbs(ygrade, ygrade);
	imshow("xgrade", xgrade);
	imshow("ygrade", ygrade);*/

	Mat xygrade = Mat(xgrade.size(), xgrade.type());
	for (int i = 0; i < src.rows; i++)
		for (int j = 0; j < src.cols; j++)
		{
			xygrade.at<uchar>(i, j) = saturate_cast<uchar>(xgrade.at<uchar>(i, j) + ygrade.at<uchar>(i, j));
		}
	imshow("xygrade", xygrade);

	addWeighted(xgrade, 0.5, ygrade, 0.5, 0, xygrade);
	imshow("addWeighted", xygrade);

	waitKey(0);
	return 0;
}

18. Laplance算子

(1)理论

(2)Laplance算子

(3)处理流程

(4)相关API

(5)演示程序

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
	Mat src = imread("C:/images/gm.jpg");
	if (src.empty()) {
		return -1;
	}
	imshow("input", src);
	
	Mat gblur, gray_src, dst;
	GaussianBlur(src, gblur, Size(3, 3), 0);
	cvtColor(gblur, gray_src, CV_BGR2GRAY);
	Laplacian(gray_src, dst, CV_16S, 3);
	convertScaleAbs(dst, dst);
	imshow("Laplance", dst);

	waitKey(0);
	return 0;
}

19. Canny边缘检测

(1)Canny算法介绍

(2)Canny算法步骤

(3)Canny算法介绍——非最大信号抑制

(4)Canny算法介绍——高低阈值输出二值图像

(5)相关API

(6)演示程序

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

Mat gray_src, dst, src;
int T1 = 50, max_value = 255;

void Canny_Demo(int, void *)
{
	Mat edge;
	blur(gray_src, gray_src, Size(3, 3), Point(-1, -1), BORDER_DEFAULT);
	Canny(gray_src, edge, T1, T1 * 2, 3, false);

	/*dst.create(src.size(), src.type());
	src.copyTo(dst, edge);*/
	imshow("output", edge);

}

int main()
{
	src = imread("C:/images/lenna.jpg");
	if (src.empty()) {
		return -1;
	}
	imshow("input", src);
	
	namedWindow("output", CV_WINDOW_AUTOSIZE);
	cvtColor(src, gray_src, CV_BGR2GRAY);
	createTrackbar("Threshold Value:", "output", &T1, max_value, Canny_Demo);
	Canny_Demo(0, 0);
	waitKey(0);
	return 0;
}

20. 霍夫变换——直线

(1)霍夫变换介绍

(2)相关API

(3)演示程序

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

Mat gray_src, dst, src;

int main()
{
	src = imread("C:/images/bin1.png");
	if (src.empty()) {
		return -1;
	}
	imshow("input", src);
	
	Canny(src, gray_src, 100, 200);
	cvtColor(gray_src, dst, CV_GRAY2BGR);
	imshow("edge", gray_src);

	vector<Vec4f> plines;
	HoughLinesP(gray_src, plines, 1, CV_PI / 180.0, 10, 0, 10);
	Scalar color = Scalar(0, 0, 255);
	for (size_t i = 0; i < plines.size(); i++)
	{
		Vec4f hline = plines[i];
		line(dst, Point(hline[0], hline[1]), Point(hline[2], hline[3]), color, 3, LINE_AA);
	}
	imshow("output", dst);

	waitKey(0);
	return 0;
}

21. 霍夫圆变换

(1)霍夫圆检测原理

(2)霍夫圆变换原理

(3)相关API

(4)演示程序

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

Mat gray_src, dst, src;

int main()
{
	src = imread("C:/images/circle.jpg");
	if (src.empty()) {
		return -1;
	}
	imshow("input", src);
	
	// 中值滤波
	Mat median_src;
	medianBlur(src, median_src, 3);
	cvtColor(median_src, median_src, CV_BGR2GRAY);

	// 霍夫圆检测
	vector<Vec3f> pcircles;
	HoughCircles(median_src, pcircles, CV_HOUGH_GRADIENT, 1, 80, 100, 30, 10, 100);
	src.copyTo(dst);
	for (size_t i = 0; i < pcircles.size(); i++)
	{
		Vec3f cc = pcircles[i];
		circle(dst, Point(cc[0], cc[1]), cc[2], Scalar(0, 0, 255), 2, LINE_AA);
		circle(dst, Point(cc[0], cc[1]), 2, Scalar(98, 3, 255), 2, LINE_AA);
	}
	imshow("output", dst);

	waitKey(0);
	return 0;
}

22. 像素重映射

(1)什么是像素重映射

(2)相关API

(3)演示程序

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

Mat map_x, map_y, dst, src;
int index;

void update_map()
{
	for (int i = 0; i < src.rows; i++)
		for (int j = 0; j < src.cols; j++)
		{
			switch (index)
			{
			case 0:
				if (j > src.cols * 0.25 && j < src.cols * 0.75 && i > src.rows * 0.25 && i < src.rows * 0.75)
				{
					map_x.at<float>(i, j) = 2 * (j - src.cols * 0.25);
					map_y.at<float>(i, j) = 2 * (i - src.rows * 0.25);
				}
				else
				{
					map_x.at<float>(i, j) = 0;
					map_y.at<float>(i, j) = 0;
				}
				break;
			case 1:
				map_x.at<float>(i, j) = (src.cols - j - 1);
				map_y.at<float>(i, j) = i;
				break;
			case 2:
				map_x.at<float>(i, j) = j;
				map_y.at<float>(i, j) = (src.rows - i - 1);
				break;
			case 3:
				map_x.at<float>(i, j) = (src.cols - j - 1);
				map_y.at<float>(i, j) = (src.rows - i - 1);
				break;
			default:
				break;
			}
		}
}

int main()
{
	src = imread("C:/images/lenna.jpg");
	if (src.empty()) {
		return -1;
	}
	imshow("input", src);
	
	map_x.create(src.size(), CV_32FC1);
	map_y.create(src.size(), CV_32FC1);

	while (true)
	{
		index = waitKey(500);
		index = index - '0';
		update_map();
		remap(src, dst, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 255));
		imshow("output", dst);
	}

	waitKey(0);
	return 0;
}

23. 直方图均衡化

(1)什么是直方图

(2)直方图均衡化

(3)图像直方图

(4)相关API

(5)演示程序

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

Mat dst, src;


int main()
{
	src = imread("C:/images/cat.jpg");
	if (src.empty()) {
		return -1;
	}
	cvtColor(src, src, CV_BGR2GRAY);
	imshow("input", src);

	equalizeHist(src, dst);
	imshow("output", dst);

	waitKey(0);
	return 0;
}

24. 直方图计算

(1)直方图概念

(2)相关API

(3)演示程序

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

Mat dst, src;

int main()
{
	src = imread("C:/images/gm.jpg");
	if (src.empty()) {
		return -1;
	}
	imshow("input", src);

	// 分通道显示
	vector<Mat> bgr_planes;
	split(src, bgr_planes);

	int histSize = 256;
	float range[] = { 0, 256 };
	const float *histRange = { range };
	Mat b_hist, g_hist, r_hist;
	calcHist(&bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange);
	calcHist(&bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange);
	calcHist(&bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange);

	// 归一化
	int hist_h = 400;
	int hist_w = 512;
	int bin_w = hist_w / histSize;
	Mat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));
	normalize(b_hist, b_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
	normalize(g_hist, g_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
	normalize(r_hist, r_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
	for (int i = 1; i < histSize; i++)
	{
		line(histImage, Point((i - 1) * bin_w, hist_h - cvRound(b_hist.at<float>(i - 1))), 
			Point(i * bin_w, hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, LINE_AA);
		line(histImage, Point((i - 1) * bin_w, hist_h - cvRound(g_hist.at<float>(i - 1))),
			Point(i * bin_w, hist_h - cvRound(b_hist.at<float>(i))), Scalar(0, 255, 0), 2, LINE_AA);
		line(histImage, Point((i - 1) * bin_w, hist_h - cvRound(r_hist.at<float>(i - 1))),
			Point(i * bin_w, hist_h - cvRound(b_hist.at<float>(i))), Scalar(0, 0, 255), 2, LINE_AA);
	}
	imshow("output", histImage);

	waitKey(0);
	return 0;
}

25. 直方图比较

(1)直方图比较方法概述

(2)直方图比较方法-相关性计算(CV_COMP_CORREL)

(3)直方图比较方法-卡方计算(CV_COMP_CHISQR)

(4) 直方图比较方法-十字计算(CV_COMP_INTERSECT)

(5)直方图比较方法-巴氏距离计算(CV_COMP_BHATTACHARYYA )

(6)相关API

(7)演示程序

#include <opencv2/opencv.hpp>
#include <cmath>

using namespace cv;
using namespace std;

Mat base, test1, test2;
Mat hsv_base, hsv_test1, hsv_test2;

int main()
{
	base = imread("C:/images/cat.jpg");
	if (base.empty()) {
		return -1;
	}
	imshow("input", base);

	test1 = imread("C:/images/cat-gray.jpg");
	test2 = imread("C:/images/lenna-noise.jpg");

	cvtColor(base, hsv_base, CV_BGR2HSV);
	cvtColor(test1, hsv_test1, CV_BGR2HSV);
	cvtColor(test2, hsv_test2, CV_BGR2HSV);

	int h_bins = 50, s_bins = 60;
	int hist_size[] = { h_bins, s_bins };

	float h_range[] = { 0, 180 };
	float s_range[] = { 0, 256 };
	const float* range[] = { h_range, s_range };

	int channels[] = { 0, 1 };
	MatND hist_base, hist_test1, hist_test2; // 多维

	calcHist(&base, 1, channels, Mat(), hist_base, 2, hist_size, range);
	calcHist(&test1, 1, channels, Mat(), hist_test1, 2, hist_size, range);
	calcHist(&test2, 1, channels, Mat(), hist_test2, 2, hist_size, range);
	normalize(hist_base, hist_base, 0, 1, NORM_MINMAX, -1, Mat());
	normalize(hist_test1, hist_test1, 0, 1, NORM_MINMAX, -1, Mat());
	normalize(hist_test2, hist_test2, 0, 1, NORM_MINMAX, -1, Mat());

	double base_base = compareHist(hist_base, hist_base, CV_COMP_CORREL);
	double base_test1 = compareHist(hist_base, hist_test1, CV_COMP_CORREL);
	double base_test2 = compareHist(hist_base, hist_test2, CV_COMP_CORREL);
	double test1_test2 = compareHist(hist_test1, hist_test2, CV_COMP_CORREL);
	//std::cout << base_test1 << endl;

	Mat temp;
	test2.copyTo(temp);
	putText(base, std::to_string(base_base), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, LINE_AA);
	putText(test1, std::to_string(base_test1), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, LINE_AA);
	putText(test2, std::to_string(base_test2), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, LINE_AA);
	putText(temp, std::to_string(test1_test2), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, LINE_AA);

	imshow("base", base);
	imshow("test1", test1);
	imshow("test2", test2);
	imshow("temp", temp);

	waitKey(0);
	return 0;
}

26. 直方图反向投影

(1)反向投影

(2)直方图反向投影步骤

(3)实现步骤与相关API

(4)演示程序

#include <opencv2/opencv.hpp>
#include <cmath>

using namespace cv;
using namespace std;

Mat src, hsv, hue;
int bins = 12;

void HistAndBackproject(int, void*) 
{
	float range[] = { 0, 180 };
	const float* hist_range = { range };
	Mat h_hist;
	calcHist(&hue, 1, 0, Mat(), h_hist, 1, &bins, &hist_range);
	normalize(h_hist, h_hist, 0, 255, NORM_MINMAX, -1, Mat());

	Mat backPrjImg;
	calcBackProject(&hue, 1, 0, h_hist, backPrjImg, &hist_range, 1, true);
	imshow("BackProject", backPrjImg);

	int hist_h = 400, hist_w = 400;
	Mat hist_image(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));
	int bin_w = hist_w / bins;
	for (int i = 1; i < bins; i++)
	{
		rectangle(hist_image,
			Point((i - 1) * bin_w, hist_h - cvRound(h_hist.at<float>(i - 1) * (400 / 255))),
			Point(i * bin_w, hist_h),
			Scalar(0, 0, 255), -1);
	}
	imshow("Histogram", hist_image);
}

int main()
{
	src = imread("C:/images/cat.jpg");
	if (src.empty()) {
		return -1;
	}
	imshow("input", src);

	cvtColor(src, hsv, CV_BGR2HSV);
	hue.create(hsv.size(), hsv.depth());
	int nchannels[] = { 0, 0 };
	mixChannels(&hsv, 1, &hue, 1, nchannels, 1);
	namedWindow("input", CV_WINDOW_AUTOSIZE);
	namedWindow("Histogram", CV_WINDOW_AUTOSIZE);

	createTrackbar("Histogram Bins", "input", &bins, 180, HistAndBackproject);
	HistAndBackproject(0, 0);

	waitKey(0);
	return 0;
}

27. 模板匹配

(1)模板匹配介绍

(2)匹配算法介绍

(3)相关API

(4)演示程序

#include <opencv2/opencv.hpp>
#include <cmath>

using namespace cv;
using namespace std;

Mat src, dst, temp;
int match_method = CV_TM_SQDIFF;
int max_track = 5;

void Math_Demo(int, void*)
{
	int witdth = src.cols - temp.cols + 1;
	int height = src.rows - temp.rows + 1;
	Mat result(witdth, height, CV_32FC1);

	matchTemplate(src, temp, result, match_method, Mat());
	normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());
	
	Point minIdx, maxIdx, tempIdx;
	double minVal, maxVal;
	minMaxLoc(result, &minVal, &maxVal, &minIdx, &maxIdx, Mat());
	src.copyTo(dst);
	if (match_method == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED)
	{
		tempIdx = minIdx;
	}
	else
	{
		tempIdx = maxIdx;
	}

	rectangle(dst, Rect(tempIdx.x, tempIdx.y, temp.cols, temp.rows), Scalar(0, 0, 255), 2, 8);
	rectangle(result, Rect(tempIdx.x, tempIdx.y, temp.cols, temp.rows), Scalar(0, 0, 255), 2, 8);

	imshow("output", result);
	imshow("match", dst);
}

int main()
{
	src = imread("C:/images/flower.jpg");
	temp = imread("C:/images/flower-temp.jpg");
	if (src.empty()) {
		return -1;
	}
	namedWindow("output", CV_WINDOW_AUTOSIZE);
	namedWindow("input", CV_WINDOW_AUTOSIZE);
	namedWindow("match", CV_WINDOW_AUTOSIZE);
	imshow("input", src);

	createTrackbar("MathType", "output", &match_method, max_track, Math_Demo);
	Math_Demo(0, 0);

	waitKey(0);
	return 0;
}

28. 轮廓发现

(1)轮廓发现

(2)相关API

(3)演示程序

#include <opencv2/opencv.hpp>
#include <cmath>

using namespace cv;
using namespace std;

Mat src, dst;
int threshold_value = 100;
int threshold_max = 255;
RNG rng;

void Demo_Contours(int, void*) 
{
	Mat canny_output;
	vector<vector<Point>> contours;
	vector<Vec4i> hierarchy;
	Canny(src, canny_output, threshold_value, threshold_value * 2, 3, false);
	findContours(canny_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));

	dst = Mat::zeros(src.size(), CV_8UC3);
	for (size_t i = 0; i < contours.size(); i++)
	{
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		drawContours(dst, contours, i, color, 2, 8, hierarchy, 0, Point(0, 0));
	}
	imshow("output", dst);
}

int main()
{
	src = imread("C:/images/happy_fish.jpg");
	if (src.empty()) {
		return -1;
	}
	namedWindow("output", CV_WINDOW_AUTOSIZE);
	namedWindow("input", CV_WINDOW_AUTOSIZE);
	cvtColor(src, src, CV_BGR2GRAY);
	imshow("input", src);

	createTrackbar("Threshold Value", "output", &threshold_value, threshold_max, Demo_Contours);
	Demo_Contours(0, 0);

	waitKey(0);
	return 0;
}

29. 凸包

(1)凸包概念

(2)Graham扫描算法

(3)相关API

(4)演示程序

#include <opencv2/opencv.hpp>
#include <cmath>

using namespace cv;
using namespace std;

Mat src, dst, gray_src;
int threshold_value = 100;
int threshold_max = 255;
RNG rng;

void Threshold_Callback(int, void*)
{
	Mat bin_output;
	vector<vector<Point>> contours;
	vector<Vec4i> hirarchy;

	threshold(gray_src, bin_output, threshold_value, threshold_max, THRESH_BINARY);
	findContours(bin_output, contours, hirarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));

	vector<vector<Point>> convex_hulls(contours.size());
	for (int i = 0; i < contours.size(); i++)
	{
		convexHull(contours[i], convex_hulls[i], false, true);
	}

	dst = Mat::zeros(src.size(), CV_8UC3);
	for (size_t i = 0; i < contours.size(); i++)
	{
		Scalar corlor = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		//drawContours(dst, contours, i, corlor, 2, 8, Mat(), 0, Point(0, 0));
		drawContours(dst, convex_hulls, i, corlor, 2, 8, Mat(), 0, Point(0, 0));
	}
	imshow("output", dst);
}

int main()
{
	src = imread("C:/images/happy_fish.jpg");
	if (src.empty()) {
		return -1;
	}
	namedWindow("output", CV_WINDOW_AUTOSIZE);
	namedWindow("input", CV_WINDOW_AUTOSIZE);
	cvtColor(src, gray_src, CV_BGR2GRAY);
	blur(gray_src, gray_src, Size(3, 3), Point(-1, -1), BORDER_DEFAULT);  
	imshow("input", gray_src);

	createTrackbar("Threshold", "output", &threshold_value, threshold_max, Threshold_Callback);
	Threshold_Callback(0, 0);

	waitKey(0);
	return 0;
}

30. 轮廓周围绘制矩形和圆形框

(1)轮廓周围绘制矩形 -API

 

(2)轮廓周围绘制圆和椭圆-API

(3)步骤

(4)演示程序

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

Mat src, gray_src, drawImg;
int threshold_v = 170;
int threshold_max = 255;
RNG rng;

void Contours_Callback(int, void*);
int main(int argc, char** argv) {
	src = imread("C:/images/balloon.jpg");
	if (!src.data) {
		return -1;
	}
	cvtColor(src, gray_src, CV_BGR2GRAY);
	blur(gray_src, gray_src, Size(3, 3), Point(-1, -1));

	namedWindow("input", CV_WINDOW_AUTOSIZE);
	namedWindow("output", CV_WINDOW_AUTOSIZE);
	imshow("input", src);

	createTrackbar("Threshold Value:", "output", &threshold_v, threshold_max, Contours_Callback);
	Contours_Callback(0, 0);

	waitKey(0);
	return 0;
}

void Contours_Callback(int, void*) {
	Mat binary_output;
	vector<vector<Point>> contours;
	vector<Vec4i> hierachy;
	threshold(gray_src, binary_output, threshold_v, threshold_max, THRESH_BINARY);
	imshow("binary image", binary_output);
	findContours(binary_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(-1, -1));

	vector<vector<Point>> contours_ploy(contours.size());
	vector<Rect> ploy_rects(contours.size());
	vector<Point2f> ccs(contours.size());
	vector<float> radius(contours.size());

	vector<RotatedRect> minRects(contours.size());
	vector<RotatedRect> myellipse(contours.size());

	for (size_t i = 0; i < contours.size(); i++) {
		approxPolyDP(Mat(contours[i]), contours_ploy[i], 3, true);
		ploy_rects[i] = boundingRect(contours_ploy[i]);
		minEnclosingCircle(contours_ploy[i], ccs[i], radius[i]);
		if (contours_ploy[i].size() > 5) {
			myellipse[i] = fitEllipse(contours_ploy[i]);
			minRects[i] = minAreaRect(contours_ploy[i]);
		}
	}

	// draw it
	drawImg = Mat::zeros(src.size(), src.type());
	Point2f pts[4];
	for (size_t t = 0; t < contours.size(); t++) {
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		//rectangle(drawImg, ploy_rects[t], color, 2, 8);
		//circle(drawImg, ccs[t], radius[t], color, 2, 8);
		if (contours_ploy[t].size() > 5) {
			ellipse(drawImg, myellipse[t], color, 1, 8);
			minRects[t].points(pts);
			for (int r = 0; r < 4; r++) {
				line(drawImg, pts[r], pts[(r + 1) % 4], color, 1, 8);
			}
		}
	}

	imshow("output", drawImg);
	return;
}

31. 图像矩

(1)矩的概念

(2)计算生成数据

(3)相关API

(4)步骤

(5)演示程序

#include <opencv2/opencv.hpp>
#include <cmath>

using namespace cv;
using namespace std;

Mat src, dst, gray_src;
int threshold_value = 100;
int threshold_max = 255;
RNG rng;

void Demo_moments(int, void*)
{
	Mat canny_output;
	vector<vector<Point>> contours;
	vector<Vec4i> hierachy;

	Canny(gray_src, canny_output, threshold_value, threshold_value * 2, 3);
	findContours(canny_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));

	vector<Moments> contours_moments(contours.size());
	for (int i = 0; i < contours.size(); i++)
	{
		contours_moments[i] = moments(contours[i]);
	}

	vector<Point2f> ccs(contours.size());
	for (int i = 0; i < contours.size(); i++)
	{
		contours_moments[i] = moments(contours[i]);
		ccs[i] = Point(static_cast<float>(contours_moments[i].m10 / contours_moments[i].m00), static_cast<float>(contours_moments[i].m01 / contours_moments[i].m00));
	}

	Mat drawImage = Mat::zeros(src.size(), CV_8UC3);
	src.copyTo(drawImage);
	for (int i = 0; i < contours.size(); i++)
	{
		cout << contourArea(contours[i]) << " " << arcLength(contours[i], true) << endl;
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		drawContours(drawImage, contours, i, color, 2, 8, hierachy, 0, Point(0, 0));
		circle(drawImage, ccs[i], 2, color, 2, 8);
	}

	imshow("output", drawImage);
}

int main()
{
	src = imread("C:/images/circle.jpg");
	if (src.empty()) {
		return -1;
	}
	namedWindow("output", CV_WINDOW_AUTOSIZE);
	namedWindow("input", CV_WINDOW_AUTOSIZE);
	cvtColor(src, gray_src, CV_BGR2GRAY);
	blur(gray_src, gray_src, Size(3, 3), Point(-1, -1));
	imshow("input", gray_src);

	createTrackbar("Threshold", "output", &threshold_value, threshold_max, Demo_moments);
	Demo_moments(0, 0);

	waitKey(0);
	return 0;
}

32. 点多边形测试

(1)点多边形概念

 

(2)相关API

(3)步骤

(4)演示程序

#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>

using namespace std;
using namespace cv;
int main(int argc, char** argv) {
	const int r = 100;
	Mat src = Mat::zeros(r * 4, r * 4, CV_8UC1);

	vector<Point2f> vert(6);
	vert[0] = Point(3 * r / 2, static_cast<int>(1.34*r));
	vert[1] = Point(1 * r, 2 * r);
	vert[2] = Point(3 * r / 2, static_cast<int>(2.866*r));
	vert[3] = Point(5 * r / 2, static_cast<int>(2.866*r));
	vert[4] = Point(3 * r, 2 * r);
	vert[5] = Point(5 * r / 2, static_cast<int>(1.34*r));

	for (int i = 0; i < 6; i++) {
		line(src, vert[i], vert[(i + 1) % 6], Scalar(255), 3, 8, 0);
	}

	vector<vector<Point>> contours;
	vector<Vec4i> hierachy;
	Mat csrc;
	src.copyTo(csrc);
	findContours(csrc, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
	Mat raw_dist = Mat::zeros(csrc.size(), CV_32FC1);
	for (int row = 0; row < raw_dist.rows; row++) {
		for (int col = 0; col < raw_dist.cols; col++) {
			double dist = pointPolygonTest(contours[0], Point2f(static_cast<float>(col), static_cast<float>(row)), true);
			raw_dist.at<float>(row, col) = static_cast<float>(dist);
		}
	}

	double minValue, maxValue;
	minMaxLoc(raw_dist, &minValue, &maxValue, 0, 0, Mat());
	Mat drawImg = Mat::zeros(src.size(), CV_8UC3);
	for (int row = 0; row < drawImg.rows; row++) {
		for (int col = 0; col < drawImg.cols; col++) {
			float dist = raw_dist.at<float>(row, col);
			if (dist > 0) {
				drawImg.at<Vec3b>(row, col)[0] = (uchar)(abs(1.0 - (dist / maxValue)) * 255);
			}
			else if (dist < 0) {
				drawImg.at<Vec3b>(row, col)[2] = (uchar)(abs(1.0 - (dist / minValue)) * 255);
			}
			else {
				drawImg.at<Vec3b>(row, col)[0] = (uchar)(abs(255 - dist));
				drawImg.at<Vec3b>(row, col)[1] = (uchar)(abs(255 - dist));
				drawImg.at<Vec3b>(row, col)[2] = (uchar)(abs(255 - dist));
			}
		}
	}

	const char* output_win = "point polygon test demo";
	char input_win[] = "input image";
	namedWindow(input_win, CV_WINDOW_AUTOSIZE);
	namedWindow(output_win, CV_WINDOW_AUTOSIZE);

	imshow(input_win, src);
	imshow(output_win, drawImg);

	waitKey(0);
	return 0;
}

31. 基于距离变换与分水岭的图像分割

(1)什么是图像分割

(2)距离变换与分水岭介绍

(3)相关API

(4)处理流程

#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>

using namespace std;
using namespace cv;

int main(int argc, char** argv) {
	Mat src = imread("C:/images/leaf.jpg");
	if (src.empty()) {
		return -1;
	}
	namedWindow("input", CV_WINDOW_AUTOSIZE);
	imshow("input", src);
	// 1. change background
	for (int row = 0; row < src.rows; row++) {
		for (int col = 0; col < src.cols; col++) {
			if (src.at<Vec3b>(row, col) == Vec3b(255, 255, 255)) {
				src.at<Vec3b>(row, col)[0] = 0;
				src.at<Vec3b>(row, col)[1] = 0;
				src.at<Vec3b>(row, col)[2] = 0;
			}
		}
	}
	namedWindow("black background", CV_WINDOW_AUTOSIZE);
	imshow("black background", src);

	// sharpen
	Mat kernel = (Mat_<float>(3, 3) << 1, 1, 1, 1, -8, 1, 1, 1, 1);
	Mat laplanceImg;
	Mat sharpenImg = src;
	filter2D(src, laplanceImg, CV_32F, kernel, Point(-1, -1), 0, BORDER_DEFAULT);
	src.convertTo(sharpenImg, CV_32F);
	Mat resultImg = sharpenImg - laplanceImg;

	resultImg.convertTo(resultImg, CV_8UC3);
	laplanceImg.convertTo(laplanceImg, CV_8UC3);
	imshow("sharpen image", resultImg);
	// src = resultImg; // copy back

	// convert to binary
	Mat binaryImg;
	cvtColor(src, resultImg, CV_BGR2GRAY);
	threshold(resultImg, binaryImg, 40, 255, THRESH_BINARY | THRESH_OTSU);
	imshow("binary image", binaryImg);

	Mat distImg;
	distanceTransform(binaryImg, distImg, DIST_L1, 3, 5);
	normalize(distImg, distImg, 0, 1, NORM_MINMAX);
	imshow("distance result", distImg);

	// binary again
	threshold(distImg, distImg, .4, 1, THRESH_BINARY);
	Mat k1 = Mat::ones(13, 13, CV_8UC1);
	erode(distImg, distImg, k1, Point(-1, -1));
	imshow("distance binary image", distImg);

	// markers 
	Mat dist_8u;
	distImg.convertTo(dist_8u, CV_8U);
	vector<vector<Point>> contours;
	findContours(dist_8u, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));

	// create makers
	Mat markers = Mat::zeros(src.size(), CV_32SC1);
	for (size_t i = 0; i < contours.size(); i++) {
		drawContours(markers, contours, static_cast<int>(i), Scalar::all(static_cast<int>(i) + 1), -1);
	}
	circle(markers, Point(5, 5), 3, Scalar(255, 255, 255), -1);
	imshow("my markers", markers * 1000);

	// perform watershed
	watershed(src, markers);
	Mat mark = Mat::zeros(markers.size(), CV_8UC1);
	markers.convertTo(mark, CV_8UC1);
	bitwise_not(mark, mark, Mat());
	imshow("watershed image", mark);

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

	// fill with color and display final result
	Mat dst = Mat::zeros(markers.size(), CV_8UC3);
	for (int row = 0; row < markers.rows; row++) {
		for (int col = 0; col < markers.cols; col++) {
			int index = markers.at<int>(row, col);
			if (index > 0 && index <= static_cast<int>(contours.size())) {
				dst.at<Vec3b>(row, col) = colors[index - 1];
			}
			else {
				dst.at<Vec3b>(row, col) = Vec3b(0, 0, 0);
			}
		}
	}
	imshow("Final Result", dst);

	waitKey(0);
	return 0;
}

 

百度已收录
  • 分享:
评论
还没有评论
    发表评论 说点什么