OpenCV学习笔记

一、OpenCV基础

(一)图像的读取、显示、创建

https://mp.weixin.qq.com/s?__biz=MzA4MTA1NjM5NQ==&mid=2247485202&idx=1&sn=05d0b4cd25675a99357910a5f2694508&chksm=9f9b80f6a8ec09e03ab2bb518ea6aad83db007c9cdd602c7459ed75c737e380ac9c34bc0d614&scene=178&cur_album_id=2073041855356764164#rd

(二)图像的属性以及像素相关的操作

https://mp.weixin.qq.com/s?__biz=MzA4MTA1NjM5NQ==&mid=2247485234&idx=1&sn=64c4a7235bd02a49d844089a84e6a01d&chksm=9f9b80d6a8ec09c029a387bbdeea3f8f7ecbc31e9032da047b6e77cf0394f272ada897c10f3b&scene=178&cur_album_id=2073041855356764164#rd

data:表示 Mat 对象中的指针(uchar 类型的指针),指向内存中存放矩阵数据的一块内存 (uchar* data)。
step: 字面意思是“步长”,实际上它描述了矩阵的形状。 step[] 为一个数组,矩阵有几维,step[] 数组就有几个元素。以一个三维矩阵为例,step[0] 表示一个平面的字节总数,step[1] 表示一行元素的字节总数,step[2] 表示每一个元素的字节总数。
上面两个数据可以配合使用来获得Mat中任意位置的数据
OpenCV学习笔记_第1张图片

(三)threshold函数的使用

https://blog.csdn.net/u012566751/article/details/77046445

图像的二值化就是将图像上的像素点的灰度值设置为0或255,这样将使整个图像呈现出明显的黑白效果。在数字图像处理中,二值图像占有非常重要的地位,图像的二值化使图像中数据量大为减少,从而能凸显出目标的轮廓。OpenCV中提供了函数cv::threshold();

(四)形态学之提取连通域

https://mp.weixin.qq.com/s?__biz=Mzg3NjY3NjI0Mw==&mid=2247484975&idx=1&sn=5ea64c7c4dd3c017eac0551f12c45137&chksm=cf2fd3d3f8585ac5b6e59f313a42d8981b8d09721f88eea7ee4a71ecfae7baeacf69fb0e1ec2&mpshare=1&scene=1&srcid=1030Tal3VDLygpiUNPLo45zv&sharer_shareinfo=84ef8c16db4fd26fa08ad0259bcc4dce&sharer_shareinfo_first=84ef8c16db4fd26fa08ad0259bcc4dce#rd

1.连通域概念:指图像中具有相同像素值且位置相邻的像素组成的区域。
2.相关函数:

int connectedComponents(InputArray image, OutputArray labels, int connectivity = 8, int ltype = CV_32S);

image:输入图像,待标记8位单通道图像。
labels:输出图像,目标标记图像。
connectivity:连通域大小,四连通域还是八连通域。
输出类型:CV32S 和 CV_16U ,默认是 CV_32S 。
返回连通域个数。

例子:

#include 
#include 

int main()
{
 cv::Mat input = cv::imread("src/rice.jpg");
 cv::Mat img_bw, connectimg;
 cv::cvtColor(input, img_bw, cv::COLOR_BGR2GRAY);
 cv::threshold(img_bw, img_bw, 100, 255, cv::THRESH_BINARY_INV);

 // 做一些膨胀和腐蚀使得图像连通域明显
 cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5));
 cv::erode(img_bw, img_bw, element, cv::Point(-1, -1), 2);
 cv::dilate(img_bw, img_bw, element, cv::Point(-1, -1), 2);

 int num = cv::connectedComponents(img_bw, connectimg, 8, CV_16U);
 std::cout << "连通域个数:" << num << std::endl;

 cv::namedWindow("原图", cv::WINDOW_NORMAL);
 cv::imshow("原图", img_bw);

 //以不同颜色标记出不同的连通域
 cv::Mat result = cv::Mat::zeros(img_bw.size(), CV_8UC3); //定义标记结果图像
 //定义五种颜色
 std::vector<cv::Vec3b> color;
 color.push_back(cv::Vec3b(0, 0, 255));
 color.push_back(cv::Vec3b(0, 255, 0));
 color.push_back(cv::Vec3b(255, 0, 0));
 color.push_back(cv::Vec3b(0, 255, 255));
 color.push_back(cv::Vec3b(255, 255, 0));

 for (int i = 0; i < result.cols; i ++)
 {
  for (int j = 0; j < result.rows; j ++)
  {
   int label = connectimg.at<uint16_t>(i, j);
   if (label == 0)
   {
    continue; //背景的黑色不改变
   }
   result.at<cv::Vec3b>(i, j) = color[label % 5];
  }
 }

 cv::namedWindow("标记连通域后", cv::WINDOW_NORMAL);
 cv::imshow("标记连通域后", result);

 cv::waitKey(0);
 return 0;
}

原始图片和更改颜色后的连通域:
OpenCV学习笔记_第2张图片

(五)距离变换distanceTransform应用——查找物体质心&&细化字符轮廓

https://www.cnblogs.com/mtcnn/p/9411967.html

distanceTransform方法的功能:
用于计算图像中每一个非零点距离离自己最近的零点的距离,distanceTransform的第二个Mat矩阵参数dst保存了每一个点与最近的零点的距离信息,图像上越亮的点,代表了离零点的距离越远

1、查找物体质心

C++

#include "core/core.hpp"
#include "imgproc/imgproc.hpp"
#include "highgui/highgui.hpp"

using namespace cv;

int main(int argc,char *argv[])
{
	float maxValue=0;  //定义距离变换矩阵中的最大值
	Point Pt(0,0);
	Mat image=imread(argv[1]);
	Mat imageGray;
	cvtColor(image,imageGray,CV_RGB2GRAY);
	imageGray=~imageGray;  //取反
	GaussianBlur(imageGray,imageGray,Size(5,5),2); //滤波
	threshold(imageGray,imageGray,20,200,CV_THRESH_BINARY); //阈值化	
	Mat imageThin(imageGray.size(),CV_32FC1); //定义保存距离变换结果的Mat矩阵
	distanceTransform(imageGray,imageThin,CV_DIST_L2,3);  //距离变换
	Mat distShow;
	distShow=Mat::zeros(imageGray.size(),CV_8UC1); //定义细化后的字符轮廓
	for(int i=0;i<imageThin.rows;i++)
	{
		for(int j=0;j<imageThin.cols;j++)
		{
			distShow.at<uchar>(i,j)=imageThin.at<float>(i,j);
			if(imageThin.at<float>(i,j)>maxValue)
			{
				maxValue=imageThin.at<float>(i,j);  //获取距离变换的极大值
				Pt=Point(j,i);  //坐标
			}
		}
	}
	normalize(distShow,distShow,0,255,CV_MINMAX); //为了显示清晰,做了0~255归一化
	circle(image,Pt,maxValue,Scalar(0,0,255),3);	
	circle(image,Pt,3,Scalar(0,255,0),3);
	imshow("Source Image",image);
	imshow("Thin Image",distShow);
	waitKey();
	return 0;
}

1).原始图片:
OpenCV学习笔记_第3张图片
2).经过距离变换后距离Mat矩阵dst:
为了显示清晰,做了0~255的归一化。可以看到,中心处最亮,说明了中心点距离零点的距离最远,而最远处就可以作为物体的质心。
OpenCV学习笔记_第4张图片
3).标记质心(绿色点):
OpenCV学习笔记_第5张图片

2、细化轮廓

C++:

#include "core/core.hpp"
#include "imgproc/imgproc.hpp"
#include "highgui/highgui.hpp"

using namespace cv;

int main(int argc,char *argv[])
{
	float maxValue=0;  //定义距离变换矩阵中的最大值
	Mat image=imread(argv[1]);
	Mat imageGray;
	cvtColor(image,imageGray,CV_RGB2GRAY);
	imageGray=~imageGray;  //取反
	GaussianBlur(imageGray,imageGray,Size(5,5),2); //滤波
	threshold(imageGray,imageGray,20,200,CV_THRESH_BINARY); //阈值
	imshow("s",imageGray);
	Mat imageThin(imageGray.size(),CV_32FC1); //定义保存距离变换结果的Mat矩阵
	distanceTransform(imageGray,imageThin,CV_DIST_L2,3);  //距离变换
	Mat distShow;
	distShow=Mat::zeros(imageGray.size(),CV_8UC1); //定义细化后的字符轮廓
	for(int i=0;i<imageThin.rows;i++)
	{
		for(int j=0;j<imageThin.cols;j++)
		{
			if(imageThin.at<float>(i,j)>maxValue)
			{
				maxValue=imageThin.at<float>(i,j);  //获取距离变换的极大值
			}
		}
	}
	for(int i=0;i<imageThin.rows;i++)
	{
		for(int j=0;j<imageThin.cols;j++)
		{
			if(imageThin.at<float>(i,j)>maxValue/1.9)
			{
				distShow.at<uchar>(i,j)=255;   //符合距离大于最大值一定比例条件的点设为255
			}
		}
	}
	imshow("Source Image",image);
	imshow("Thin Image",distShow);
	waitKey();
	return 0;
}

1.原始图像:
OpenCV学习笔记_第6张图片
2.细化效果:
OpenCV学习笔记_第7张图片

二、 形态学操作之腐蚀与膨胀

https://blog.csdn.net/qq_42856191/article/details/123663533

(一)腐蚀(erosion)

1.1 什么是腐蚀
简单来说,腐蚀就是把图像中的物体变小了!(用背景去侵蚀前景)

腐蚀的工作过程如下图所示,A是一个集合,B是一个结构单元,我们使用B去对集合A进行腐蚀,腐蚀过程如C所示,在腐蚀过程中,结构单元必须全部位于集合A中才能进行腐蚀操作,最终得到的结果即为D所示。
OpenCV学习笔记_第8张图片
Python:

import cv2
import numpy as np


ori = cv2.imread(r"C:\Users\Lenovo\Desktop\original.jpg")   # 读取图像

kernel1 = np.ones((3, 3), np.uint8)     # 3个不同尺度的腐蚀单元
kernel2 = np.ones((5, 5), np.uint8)
kernel3 = np.ones((7, 7), np.uint8)

erosion1 = cv2.erode(ori, kernel1)		# 腐蚀函数
erosion2 = cv2.erode(ori, kernel2)
erosion3 = cv2.erode(ori, kernel3)

cv2.imshow("original", ori)
cv2.imshow("erosion1", erosion1)
cv2.imshow("erosion2", erosion2)
cv2.imshow("erosion3", erosion3)

cv2.imwrite(r'C:\Users\Lenovo\Desktop\erosion1.jpg', erosion1)
cv2.imwrite(r'C:\Users\Lenovo\Desktop\erosion2.jpg', erosion2)
cv2.imwrite(r'C:\Users\Lenovo\Desktop\erosion3.jpg', erosion3)

cv2.waitKey()

下面展示的是程序得到的结果图,由图可知,腐蚀能对图像中的毛刺进行去除,但这也与腐蚀单元的大小有关,3 × 3 3×33×3大小的核去除效果不如5 × 5 5×55×5与7 × 7 7×77×7,此外7 × 7 7×77×7的核使得图像变得更加细小。
OpenCV学习笔记_第9张图片

(二)膨胀(dilation)

2.1 什么是膨胀
简单来说,膨胀就是把图像中的物体变大了!(对前景进行膨胀)

膨胀的工作过程如下图所示,A是一个集合,B是一个结构单元,我们使用B去对集合A进行膨胀,膨胀过程如C所示,在膨胀过程中,结构单元只要有一个位于集合A中就能进行膨胀操作,最终得到的结果即为D所示。
OpenCV学习笔记_第10张图片
Python:

import cv2
import numpy as np


ori = cv2.imread(r"C:\Users\Lenovo\Desktop\original.jpg")   # 读取图像

kernel1 = np.ones((3, 3), np.uint8)     # 3个不同尺度的腐蚀单元
kernel2 = np.ones((5, 5), np.uint8)
kernel3 = np.ones((9, 9), np.uint8)

dilation1 = cv2.dilate(ori, kernel1)    # 膨胀函数
dilation2 = cv2.dilate(ori, kernel2)
dilation3 = cv2.dilate(ori, kernel3)

cv2.imshow("original", ori)
cv2.imshow("dilation1", dilation1)
cv2.imshow("dilation2", dilation2)
cv2.imshow("dilation3", dilation3)

cv2.imwrite(r'C:\Users\Lenovo\Desktop\dilation1.jpg', dilation1)
cv2.imwrite(r'C:\Users\Lenovo\Desktop\dilation2.jpg', dilation2)
cv2.imwrite(r'C:\Users\Lenovo\Desktop\dilation3.jpg', dilation3)

cv2.waitKey()

下面展示的是程序得到的结果图,由图可知,膨胀能对图像中的物体进行扩张,但这也与膨胀单元的大小有关,越大的膨胀核使得图像扩张区域更大。
OpenCV学习笔记_第11张图片

三、形态学操作之开运算与闭运算

https://blog.csdn.net/qq_42856191/article/details/123670455

(一)开运算

1.1 什么是开运算:先腐蚀后膨胀的操作称为开运算。
1.2作用:消除细小物体、在窄区域分离物体、平滑大物体边界等。
OpenCV学习笔记_第12张图片

(二)闭运算

2.1 什么是闭运算:先膨胀后腐蚀的操作称为闭运算。
2.2作用:填充物体空洞、消除噪声、连接邻近物体、平滑边界等。
OpenCV学习笔记_第13张图片

四、图像分割 – 距离变换与分水岭算法(硬币检测、扑克牌检测、车道检测)

https://blog.csdn.net/great_yzl/article/details/119831771

以上述引用中的硬币检测为例子的分割过程:
1.将RGB图片转换为灰度图
2.去噪
开运算:先侵蚀后膨胀。会将两个物体之间可能存在的粘连噪点过滤,并将前景物体扩大。
3.确定背景区域
对图片进行膨胀操作,将前景扩大,背景也会随之减小。那么此时对象>原对象,此时背景 < 原背景,那么此时的背景自然可以确定为原背景的一部分。(离对象中心很远的是背景)
4.确定前景区域
原理:距离变换,在二值图中把对象缩小,得到的就是原图的一部分,可以确定为前景。
这种距离变换可以将前景中的不同实例分离,距离变换后得到前景物体不同灰度值的像素,通过threshold函数选定一个阈值来缩小前景物体中每个的大小,从而达到将不同实例分离的效果。(不分离的话,可以不用距离变换,只用腐蚀就够了)
下图分别为img原始图片、opening膨胀后的图片、sure_fg距离变换后经过threshold阈值操作获得的确定前景实例
OpenCV学习笔记_第14张图片

你可能感兴趣的:(opencv,opencv,学习,笔记)