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;
}
百度已收录