OpenCV【未完结】
1_图片读取与显示
imread()函数:读取图片
param1:图片的名称
如果当前读入的图片与该脚本在相同目录下,则路径可以为相对路径
如果当前读入的图片不与该脚本在相同目录下,则路径可以为绝对路径
param2:常见的为以下三种
IMREAD_UNCHANGED = -1, 按原样返回加载的图像(使用alpha通道,否则会被裁剪)。忽略EXIF方向。
IMREAD_GRAYSCALE = 0, 始终将图像转换为单通道灰度图像(编解码器内部转换)。
IMREAD_COLOR = 1, 始终将图像转换为3通道BGR彩色图像。
namewindow()函数:打开桌面窗口
param2:
WINDOW_NORMAL 用户可以调整窗口大小(无限制)/也可以将全屏窗口切换到正常大小。
WINDOW_AUTOSIZE 用户无法调整窗口大小,窗口大小受显示图像的限制。
imshow():图片显示
parm1:所要显示的窗口,若不存在便创建一个新的窗口
parm2:所要显示的照片
waitKey(0):将显示窗口停留,不会一闪而过显示图像
输入图片:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int artc, char** argv) {
Mat src = imread("./test.png", IMREAD_GRAYSCALE);
if (src.empty()) {
cput<<"could not load image..."<<endl;
return -1;
}
namedWindow("input", CV_WINDOW_AUTOSIZE);
imshow("input", src);
waitKey(0);
return 0;
}
输出图片:
2_图片灰度化
cvtColor(src, gray, COLOR_BGR2GRAY)
param1:输入图像
param2:输出图像
param3:为转换类型,详细类型请查看源码参数
输入图片:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int artc, char** argv) {
Mat src = imread("./test.png");
if (src.empty()) {
cout<<"could not load image..."<<endl;
return -1;
}
namedWindow("input", CV_WINDOW_AUTOSIZE);
imshow("input", src);
Mat gray;
cvtColor(src, gray, COLOR_BGR2GRAY);
imwrite("./gray.png", gray);
waitKey(0);
return 0;
}
输入图片:
3_图像创建与赋值
.clone()函数:clone是把所有的都复制过来,不论你是否设置了ROI、COI等影响,clone都会原封不动的克隆过来。会为其分配新内存
.copyTo()函数:copyTo不会为目标矩阵重新分配内存,拷贝src到m2中
param1:矩阵的行
param2:矩阵的列
param3:类型 CV_8UC3表示为8位三通道 U为unsigned
Mat_(2,3)<<0,1,2,4,5,6;
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int artc, char** argv) {
Mat src = imread("./test.png");
if (src.empty()) {
cout<<"could not load image..."<<endl;
return -1;
}
namedWindow("input", CV_WINDOW_AUTOSIZE);
imshow("input", src);
Mat m1 = src.clone();
Mat m2;
src.copyTo(m2);
Mat m3 = src;
Mat m4 = Mat::zeros(src.size(), src.type());
Mat m5 = Mat::zeros(Size(512, 512), CV_8UC3);
Mat m6 = Mat::ones(Size(512, 512), CV_8UC3);
Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0,
-1, 5, -1,
0, -1, 0);
waitKey(0);
return 0;
}
4_图像像素读写
Vec3b:Vec3b可以看作是vector<uchar, 3>,可以理解为一个uchar类型的,长度为3的vector向量
src.rows:图像的行
src.cols:图像的列
src.channels():图像的通道数
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int artc, char** argv) {
Mat src = imread("");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
//获取图像的长、宽、通道
int height = src.rows;
int width = src.cols;
int ch = src.channels();
for (int c = 0; c < ch; c++)
{
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
if (ch == 3) //若为3通道图像
{
Vec3b bgr = src.at<Vec3b>(row, col);
bgr[0] = 255 - bgr[0];//反转颜色
bgr[1] = 255 - bgr[1];
bgr[2] = 255 - bgr[2];
src.at<Vec3b>(row, col) = bgr;
}
else if (ch == 1) //若为灰度图
{
int gray = src.at<uchar>(row, col);
src.at<uchar>(row, col) = 255 - gray;//反转颜色
}
}
}
}
imshow("output", src);
//利用指针遍历
Mat result = Mat::zeros(src.size(), src.type());
int blue = 0, green = 0, red = 0;
int gray;
for (int c = 0; c < ch; c++)
{
for (int row = 0; row < height; row++)
{
uchar* curr_row = src.ptr<uchar>(row);//行指针
uchar* result_row = result.ptr<uchar>(row);
for (int col = 0; col < width; col++)
{
if (ch == 3)
{
blue = *curr_row++;//先++后取值
green = *curr_row++;
red = *curr_row++;
*result_row++ = blue;
*result_row++ = green;
*result_row++ = red;
}
else if (ch == 1)
{
gray = *curr_row++;
*result_row++ = gray;
}
}
}
}
imshow("result", result);
waitKey(0);
return 0;
}
5_图像像素操作(加减乘除)
saturate_cast():防止像素外溢 运算完之后,结果为负,则转为0,结果超出255,则为255
add():像素相加
subtract():像素相减
multiply():像素相乘
divide():像素相除
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int artc, char** argv) {
Mat src1 = imread("");
Mat src2 = imread("");
if (src1.empty() || src2.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input1", src1);
imshow("input2", src2);
int height = src1.rows;
int width = src1.cols;
int b1 = 0, g1 = 0, r1 = 0;
int b2 = 0, g2 = 0, r2 = 0;
int b = 0, g = 0, r = 0;
Mat result = Mat::zeros(src1.size(), src1.type());
//代码实现两图像相加
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
b1 = src1.at<Vec3b>(row, col)[0];
g1 = src1.at<Vec3b>(row, col)[1];
r1 = src1.at<Vec3b>(row, col)[2];
b2 = src2.at<Vec3b>(row, col)[0];
g2 = src2.at<Vec3b>(row, col)[1];
r2 = src2.at<Vec3b>(row, col)[2];
result.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(b1 + b2);
//saturate_cast防止像素外溢 运算完之后,结果为负,则转为0,结果超出255,则为255
result.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(g1 + g2);
result.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(r1 + r2);
}
}
imshow("output", result);
Mat add_result = Mat::zeros(src1.size(), src1.type());
//API实现图像相加
add(src1, src2, add_result);
imshow("add_result", add_result);
Mat sub_result = Mat::zeros(src1.size(), src1.type());
//API实现图像相减
subtract(src1, src2, sub_result);
imshow("sub_result", sub_result);
Mat mul_result = Mat::zeros(src1.size(), src1.type());
//API实现图像相乘
multiply(src1, src2, mul_result);
imshow("mul_result", mul_result);
Mat div_result = Mat::zeros(src1.size(), src1.type());
//API实现图像相除
divide(src1, src2, div_result);
imshow("div_result", div_result);
waitKey(0);
return 0;
}
输入图片1:
输入图片2:
输出图片1:
输出图片2:
输出图片3:
输出图片4:
输出图片5:
6_图像伪色彩增强
applyColorMap():将灰度图像转换成彩色图像,转换的模式达22种之多。详细接口形式可看源码
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
void customColorMap(Mat& image);
int main(int argc, const char* argv[])
{
Mat src = imread("");
if (src.empty())
{
printf("could not load image...\n");
return -1;
}
Mat gray, dst;
applyColorMap(src, dst, COLORMAP_SUMMER);//将灰度图像转换成彩色图像
imshow("colorMap", dst);
cvtColor(src, gray, COLOR_BGR2GRAY);//灰度化
imshow("gray", gray);
customColorMap(gray);
waitKey(0);
return 0;
}
void customColorMap(Mat& image) //二值化
{
int lut[256];
for (int i = 0; i < 256; i++)
{
if (i < 127)
lut[i] = 0;
else
lut[i] = 255;
}
int h = image.rows;
int w = image.cols;
for (int row = 0; row < h; row++)
{
for (int col = 0; col < w; col++)
{
int pv = image.at<uchar>(row, col);
image.at<uchar>(row, col) = lut[pv];
}
}
imshow("lut demo", image);
}
输入图片:
输出图片1:
输出图片2:
输出图片3:
7_图像像素操作(逻辑操作)
Rect:类成员变量x、y、width、height,分别为左上角点的坐标和矩形的宽和高
成员属性:
size()和area():
size()函数返回值就是一个size类型的变量,包括矩形的宽度和高度,area()函数返回了矩形的面积。
br()和tl():
br()返回右下角坐标(BottomRight),tl()返回矩形左上角坐标(TopLeft)。返回值类型均为Point
contains()和inside():
返回值为bool类型,用来描述点和矩形的相对位置的。
Sclar:用来设置颜色。三通道颜色排列顺序 B G R
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, const char* argv[])
{
//创建第一个图片 400*400 三通道
Mat src1 = Mat::zeros(Size(400, 400), CV_8UC3);
//Rect类 x,y,height,width
Rect rect(100, 100, 100, 100);
src1(rect) = Scalar(0, 0, 255);
imshow("input1", src1);
printf("create first image...\n");
//创建第二个图片
Mat src2 = Mat::zeros(Size(400, 400), CV_8UC3);
rect.x = 150;
rect.y = 150;
src2(rect) = Scalar(0, 0, 255);
imshow("input2", src2);
printf("create second image...\n");
Mat dst1, dst2, dst3;
bitwise_and(src1, src2, dst1);//像素与
bitwise_xor(src1, src2, dst2);//像素异或
bitwise_or(src1, src2, dst3);//像素或
imshow("dst1", dst1);
imshow("dst2", dst2);
imshow("dst3", dst3);
Mat src = imread("test.png");
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
Mat dst;
bitwise_not(src, dst);//像素非
imshow("dst", dst);
waitKey(0);
return 0;
}
输入图像:
输出图像1:
输出图像2:
输出图像3:
输出图像4:
输出图像5:
输出图像6:
输出图像7:
8_图像通道分离合并
**split()😗*图像通道的分离
**merge()😗*图像通道的合并
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, const char* argv[])
{
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
vector<Mat> mv;
Mat dst1, dst2, dst3;
//图像通道的分离
split(src, mv);
mv[0] = Scalar(0);//B设为0 G 和 R混合
//通道的合并
merge(mv, dst1);
imshow("output1", dst1);
split(src, mv);
mv[1] = Scalar(0);//G设为0 B 和 R混合
merge(mv, dst2);
imshow("output2", dst2);
split(src, mv);
mv[2] = Scalar(0);//R设为0 B 和 G混合
merge(mv, dst3);
imshow("output3", dst3);
waitKey(0);
return 0;
}
输入图片:
输出图片1:
输出图片2:
输出图片3:
9_色彩空间转换
inRange():
inRange()函数可实现二值化功能(这点类似threshold()函数),可同时针对多通道进行操作.主要是将在两个阈值内的像素值设置为白色(255),而不在阈值区间内的像素值设置为黑色(0).
void inRange(InputArray src, InputArray lowerb,InputArray upperb, OutputArray dst)
param1:输入要处理的图像,可以为单通道或多通道。
param2:包含下边界的数组或标量。
param3:包含上边界数组或标量。
param4:输出图像,与输入图像src 尺寸相同且为CV_8U 类型。
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, const char* argv[])
{
Mat src = imread("test.jpg");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
// RGB to HSV
Mat hsv;
cvtColor(src, hsv, COLOR_BGR2HSV);
imshow("hsv", hsv);
// RGB to YUV
Mat yuv;
cvtColor(src, yuv, COLOR_BGR2YUV);
imshow("yuv", yuv);
// RGB to YUV
Mat ycrcb;
cvtColor(src, ycrcb, COLOR_BGR2YCrCb);
imshow("ycrcb", ycrcb);
Mat src2 = imread("test.png");
imshow("src2", src2);
cvtColor(src2, hsv, COLOR_BGR2HSV);
Mat mask;
inRange(hsv, Scalar(35, 43, 46), Scalar(99, 255, 255), mask);
imshow("mask", mask);
waitKey(0);
return 0;
}
输入图像1:输出图像1:
输出图像2:
输出图像3:
输入图像2:
输出图像4:
10_图像像素值统计
void minMaxLoc(InputArray src, CV_OUT double minVal,
CV_OUT double maxVal = 0, CV_OUT Point* minLoc = 0,
CV_OUT Point* maxLoc = 0, InputArray mask = noArray())**
param1:InputArray类型的src,输入单通道数组(图像)。
param2:double类型的minVal,返回最小值的指针。若无须返回,此值置为NULL。
param3:double类型的maxVal,返回最大值的指针。若无须返回,此值置为NULL。
param4:Point类型的minLoc,返回最小位置的指针(二维情况下)。若无须返回,此值置为NULL。
param5:Point类型的maxLoc,返回最大位置的指针(二维情况下)。若无须返回,此值置为NULL。
param6:InputArray类型的mask,用于选择子阵列的可选掩膜。
Point类:可以用来存放一些坐标信息,将x,y封装在point类
属性和方法:Point point = new Point(1,2)
point.x 获取int型的对应x坐标值
point.y获取int型的对应y坐标值
point.getX()获取double型的x坐标值
point.getY()获取double型的y坐标值
meanStdDev():计算矩阵的均值和标准偏差。
void meanStdDev(InputArray src, OutputArray mean, OutputArray stddev,
InputArray mask=noArray())
src:输入矩阵,此矩阵是1-4通道的
mean:输出参数,计算均值
stddev:输出参数,计算标准差
mask:可选参数
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, const char* argv[])
{
Mat src = imread("test.png", IMREAD_GRAYSCALE);
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
double minVal; double maxVal; Point minLoc; Point maxLoc;
minMaxLoc(src, &minVal, &maxVal, &minLoc, &maxLoc, Mat());
printf("min: %.2f, max: %.2f \n", minVal, maxVal);
printf("min loc: (%d, %d) \n", minLoc.x, minLoc.y);
printf("max loc: (%d, %d)\n", maxLoc.x, maxLoc.y);
src = imread("test.png");
Mat means, stddev;
meanStdDev(src, means, stddev);
printf("blue channel->> mean: %.2f, stddev: %.2f\n", means.at<double>(0, 0), stddev.at<double>(0, 0));
printf("green channel->> mean: %.2f, stddev: %.2f\n", means.at<double>(1, 0), stddev.at<double>(1, 0));
printf("red channel->> mean: %.2f, stddev: %.2f\n", means.at<double>(2, 0), stddev.at<double>(2, 0));
waitKey(0);
return 0;
}
输入图片:
输出:
11_图像像素归一化
convertTo(dst, type, scale, shift):
dst:目的矩阵;
type:需要的输出矩阵类型,或者更明确的,是输出矩阵的深度,如果是负值(常用-1)则输出矩阵和输入矩阵类型相同;
scale:比例因子;
shift:将输入数组元素按比例缩放后添加的值;
dst(i)=src(i) * scale + shift
说明:不是所有格式的Mat型数据都能被使用保存为图片,目前OpenCV主要只支持单通道和3通道的图像,并且此时要求其深度为8bit和16bit无符号(即CV_16U),所以其他一些数据类型是不支持的,比如float型等。若Mat类型数据的深度和通道数不满足要求,则需使用convertTo()函数和cvtColor()函数进行转换。
convertTo()函数负责转换数据类型不同的Mat,即可将类似float型的Mat转换到imwrite()函数能够接受的类型。
cvtColor()函数是转换不同通道的Mat,因为该函数的第4个参数就可以设置目的Mat数据的通道数
void normalize( InputArray src, InputOutputArray dst, double alpha = 1, double beta = 0,
int norm_type = NORM_L2, int dtype = -1, InputArray mask = noArray());
归一化就是要把需要处理的数据经过处理后(通过某种算法)限制在所需要的一定范围内。
param5:归一化方式选择
NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化。
NORM_INF: 归一化数组的(切比雪夫距离)L∞范数(绝对值的最大值)
NORM_L1 : 归一化数组的(曼哈顿距离)L1-范数(和的绝对值)
NORM_L2: 归一化数组的(欧几里德距离)L2-范数
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, const char* argv[])
{
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
Mat gray, gray_f;
cvtColor(src, gray, COLOR_BGR2GRAY);
// 转换为单通道32位浮点类型
gray.convertTo(gray, CV_32F);
//通过NORM_MINMAX归一化
Mat dst = Mat::zeros(gray.size(), CV_32FC1);
normalize(gray, dst, 1.0, 0, NORM_MINMAX);
Mat result = dst * 255;
result.convertTo(dst, CV_8UC1);
imshow("NORM_MINMAX", dst);
// 通过NORM_INF归一化
normalize(gray, dst, 1.0, 0, NORM_INF);
result = dst * 255;
result.convertTo(dst, CV_8UC1);
imshow("NORM_INF", dst);
//通过NORM_L1归一化
normalize(gray, dst, 1.0, 0, NORM_L1);
result = dst * 10000000;
result.convertTo(dst, CV_8UC1);
imshow("NORM_L1", dst);
//通过NORM_L2归一化
normalize(gray, dst, 1.0, 0, NORM_L2);
result = dst * 10000;
result.convertTo(dst, CV_8UC1);
imshow("NORM_L2", dst);
waitKey(0);
return 0;
}
输入图片:
输出图片1:
输出图片2:
输出图像3
输出图像4
12_视频读写
VideoCapture():从视频文件或摄像机中捕获视频的类是VideoCapture
capture.open(): 检测是否正常打开:成功打开时,isOpened返回ture
VideoCapture::get()CV.CAP_PROP_POS_MSEC 0 当前视频文件的时间位置(返回毫秒)或视频捕获时间戳
CV.CAP_PROP_POS_FRAMES 1 从0开始的解码/捕获时间帧
CV.CAP_PROP_POS_AVI_RATIO 2 返回视频文件的相关位置:0,视频开始。1,视频结束
CV.CAP_PROP_FRAME_WIDTH 3 视频流中的帧宽
CV.CAP_PROP_FRAME_HEIGHT 4 视频流中的帧高
CV.CAP_PROP_FPS 5 帧率
CV.CAP_PROP_FOURCC 6 返回解码方式中的四字符
CV.CAP_PROP_FRAME_COUNT 7 视频文件的总帧数
CV.CAP_PROP_FORMAT 8 由retrieve()函数返回的矩阵对象的格式
CV.CAP_PROP_MODE 9 用于预测当前捕获模式的后端专用值
CV.CAP_PROP_BRIGHTNESS 10 图像的亮度(仅用于摄像头)
CV.CAP_PROP_CONTRAST 11 图像的对比度(仅用于摄像头)
CV.CAP_PROP_SATURATION 12 图像的饱和度(仅用于摄像头)
CV.CAP_PROP_HUE 13 图像的色调(仅用于摄像头)
CV.CAP_PROP_GAIN 14 图像增益(仅用于摄像头)
CV.CAP_PROP_EXPOSURE 15 曝光度(仅用于摄像头)
CV.CAP_PROP_CONVERT_RGB 16 用于预测图像是否应该被转换为RGB的布尔位
CV.CAP_PROP_WHITE_BALANCE 17 白平衡(当前不支持)
CV.CAP_PROP_RECTIFICATION 18 立体相机的纠正位
VideoWriter类:视频的写操作
cv::VideoWriter out(
const string& filename, // 输入文件名
int fourcc, // 编码形式,使用 CV_FOURCC()宏
double fps, // 输出视频帧率
cv::Size frame_size, // 单帧图片的大小
bool is_color = true // 如果是false,可传入灰度图像
);
eg:
cv::VideoWriter out;
out.open(
“my_video.mpg”, //视频文件名和路径
CV_FOURCC(‘D’,‘I’,‘V’,‘X’), // MPEG-4 编码
30.0, // 帧率 (FPS)
cv::Size( 640, 480 ), // 单帧图片分辨率为 640x480
true // 只输入彩色图
);
CV_FOURCC编码格式
CV_FOURCC(‘P’, ‘I’, ‘M’, ‘1’) = MPEG-1 codec
CV_FOURCC(‘M’, ‘J’, ‘P’, ‘G’) = motion-jpeg codec
CV_FOURCC(‘M’, ‘P’, ‘4’, ‘2’) = MPEG-4.2 codec
CV_FOURCC(‘D’, ‘I’, ‘V’, ‘3’) = MPEG-4.3 codec
CV_FOURCC(‘D’, ‘I’, ‘V’, ‘X’) = MPEG-4 codec
CV_FOURCC(‘U’, ‘2’, ‘6’, ‘3’) = H263 codec
CV_FOURCC(‘I’, ‘2’, ‘6’, ‘3’) = H263I codec
CV_FOURCC(‘F’, ‘L’, ‘V’, ‘1’) = FLV1 codec
VedioCapture::read():将视频帧读取到cv::Mat矩阵中:一种是read()操作;另一种是 “>>”操作。
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
VideoCapture capture;
capture.open("test.avi");
if (!capture.isOpened()) {
printf("could not read this video file...\n");
return -1;
}
Size S = Size((int)capture.get(CAP_PROP_FRAME_WIDTH),
(int)capture.get(CAP_PROP_FRAME_HEIGHT));
int fps = capture.get(CAP_PROP_FPS);
printf("current fps : %d \n", fps);
VideoWriter writer("./test_cp.mp4", VideoWriter::fourcc('D', 'I', 'V', 'X'), fps, S, true);
Mat frame;
namedWindow("camera-demo", WINDOW_AUTOSIZE);
while (capture.read(frame)) {
imshow("camera-demo", frame);
writer.write(frame);
char c = waitKey(50);
if (c == 27) {
break;
}
}
capture.release();
writer.release();
waitKey(0);
return 0;
}
13_图像翻转
void cv::flip(
cv::InputArray src, // 输入图像
cv::OutputArray dst, // 输出
int flipCode = 0 // >0:
);沿y-轴翻转, 0: 沿x-轴翻转, <0: x、y轴同时翻转
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
Mat src = imread("./test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
imshow("input", src);
Mat dst;
// X 翻转
flip(src, dst, 0);
imshow("x-flip", dst);
// Y 翻转
flip(src, dst, 1);
imshow("y-flip", dst);
// XY 翻转
flip(src, dst, -1);
imshow("xy-flip", dst);
waitKey(0);
return 0;
}
输入图片:
输出图片1
输出图片2
输出图片3
14_图像插值
void resize(InputArray src, OutputArray dst, Size dsize, double fx=0, double fy=0, int interpolation=INTER_LINEAR );
src:输入,原图像,即待改变大小的图像;
dst:输出,改变大小之后的图像,这个图像和原图像具有相同的内容,只是大小和原图像不一样而已;
dsize:输出图像的大小。如果这个参数不为0,那么就代表将原图像缩放到这个Size(width,height)指定的大小;如果这个参数为0,那么原图像缩放之后的大小就要通过下面的公式来计算:
dsize = Size(round(fxsrc.cols), round(fysrc.rows))
其中,fx和fy就是下面要说的两个参数,是图像width方向和height方向的缩放比例。
fx:width方向的缩放比例,如果它是0,那么它就会按照(double)dsize.width/src.cols来计算;
fy:height方向的缩放比例,如果它是0,那么它就会按照(double)dsize.height/src.rows来计算;
interpolation:这个是指定插值的方式,图像缩放之后,肯定像素要进行重新计算的,就靠这个参数来指定重新计算像素的方式,有以下几种:
INTER_NEAREST - 最邻近插值
INTER_LINEAR - 双线性插值,如果最后一个参数你不指定,默认使用这种方法
INTER_AREA -区域插值
INTER_CUBIC - 4x4像素邻域内的双立方插值
INTER_LANCZOS4 - 8x8像素邻域内的Lanczos插值
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
imshow("input", src);
int h = src.rows;
int w = src.cols;
float fx = 0.0, fy = 0.0;
Mat dst = Mat::zeros(src.size(), src.type());
resize(src, dst, Size(w * 2, h * 2), fx = 0, fy = 0, INTER_NEAREST);
imshow("INTER_NEAREST", dst);//最邻近插值
resize(src, dst, Size(w * 2, h * 2), fx = 0, fy = 0, INTER_LINEAR);
imshow("INTER_LINEAR", dst);//双线性插值
resize(src, dst, Size(w * 2, h * 2), fx = 0, fy = 0, INTER_CUBIC);
imshow("INTER_CUBIC", dst);//4x4像素邻域内的双立方插值
resize(src, dst, Size(w * 2, h * 2), fx = 0, fy = 0, INTER_LANCZOS4);
imshow("INTER_LANCZOS4", dst);//8x8像素邻域内的Lanczos插值*
waitKey(0);
return 0;
}
输入图片
输出图片1
输出图片2:
输出图片3
输出图片4
15_绘制集合形状
void cv::rectangle ( InputOutputArray img,
Point pt1,
Point pt2,
const Scalar & color,
int thickness = 1,
int lineType = LINE_8,
int shift = 0
) //绘制一个简单的、粗的或填充的直角矩形或直角矩形框。
img 图像。
pt1 矩形的顶点。
pt2 与 pt1 相对的矩形的顶点。意思是pt1和pt2是对角顶点
color 颜色或亮度(灰度图像)。
thickness 构成矩形的线条的厚度。负值,如 FILLED、-1,意味着函数必须绘制一个填充的矩形。
lineType 线的类型。
shift 点坐标中的小数位数,一般取0,因为像素一般都是整型值。
RNG类(Random number generator):opencv 里RNG类构造函数初始化为固定值后,随机种子也是固定的,因此在相同的平台环境下,编译后每次运行它,显示的随机数是一样的。
**RNG(int seed):**使用种子seed产生一个64位随机整数,默认-1
**RNG::uniform( ) :**产生一个均匀分布的随机数
RNG::gaussian( ) : 产生一个高斯分布的随机数
RNG::uniform(a, b ) 返回一个[a,b)范围的均匀分布的随机数,a,b的数据类型要一致,而且必须是int、float、double中的一种,默认是int。
RNG::gaussian( σ) 返回一个均值为0,标准差为σ的随机数。setTo()函数:opencv的setTo函数是将图像设置为某个值,Mat src,想将他的值全部设置成0,则src.setTo(0)另,比如,对于一个已知的src,我们要将大于或者小于某个值的像素值设置为指定的值,则src.setTo(0,src < 10);
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
Mat image = Mat::zeros(Size(512, 512), CV_8UC3);
Rect rect(100, 100, 200, 200);
rectangle(image, rect, Scalar(255, 0, 0), 2, LINE_8, 0);
circle(image, Point(256, 256), 50, Scalar(0, 0, 255), 2, LINE_8, 0);
ellipse(image, Point(256, 256), Size(150, 50), 360, 0, 360, Scalar(0, 255, 0), 2, LINE_8, 0);
imshow("image", image);
waitKey(0);
RNG rng(0xFFFFFF);
image.setTo(Scalar(0, 0, 0));
for (int i = 0; i < 100000; i++)
{
int x1 = rng.uniform(0, 512);
int y1 = rng.uniform(0, 512);
int x2 = rng.uniform(0, 512);
int y2 = rng.uniform(0, 512);
int b = rng.uniform(0, 256);
int g = rng.uniform(0, 256);
int r = rng.uniform(0, 256);
line(image, Point(x1, y1), Point(x2, y2), Scalar(b, g, r), 1, LINE_AA, 0);
imshow("image", image);
char c = waitKey(20);
if (c == 27)
break;
imshow("image", image);
}
waitKey(0);
return 0;
}
输出图片1:
输出图片2
16_图像ROI与ROI操作
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
Mat src = imread("test.png");
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
int h = src.rows;
int w = src.cols;
// 设置ROI
int cy = h / 2;
int cx = w / 2;
Rect rect(cx - 100, cy - 100, 200, 200);
Mat roi = src(rect);
imshow("roi", roi);
Mat image = roi.clone();
// 修改 ROI B
roi.setTo(Scalar(255, 0, 0));
imshow("result", src);
// 修改 ROI R
image.setTo(Scalar(0, 0, 255));
imshow("result", src);
imshow("copy roi", image);
// example with ROI - generate mask
Mat src2 = imread("test.png");
imshow("src2", src2);
Mat hsv, mask;
cvtColor(src2, hsv, COLOR_BGR2HSV);
inRange(hsv, Scalar(35, 43, 46), Scalar(99, 255, 255), mask);
imshow("mask", mask);
// ROI非 与
Mat person;
bitwise_not(mask, mask);
bitwise_and(src2, src2, person, mask);
imshow("person", person);
// 生成背景
Mat result = Mat::zeros(src2.size(), src2.type());
result.setTo(Scalar(255, 0, 0));
// 结合
Mat dst;
bitwise_not(mask, mask);
bitwise_or(person, result, dst, mask);
add(dst, person, dst);
imshow("dst", dst);
waitKey(0);
return 0;
}
17_图像直方图
void calcHist( const Mat* images, int nimages,
const int* channels, InputArray mask,
OutputArray hist, int dims, const int* histSize,
const float** ranges, bool uniform=true, bool accumulate=false );
参数解释:
• images:输入的图像的指针;
• nimages:输入图像个数;
• channels:需要统计直方图的第几通道;
• mask:掩模,mask必须是一个8位(CV_8U)的数组并且和images的数组大小相同;
• hist:直方图计算的输出值;
• dims:输出直方图的维度(由channels指定);
• histSize:直方图中每个dims维度需要分成多少个区间(如果把直方图看作一个一个竖条的话,就是竖条的个数);
• ranges:统计像素值的区间;
• uniform=true:是否对得到的直方图数组进行归一化处理;
• accumulate=false:在多个图像时,是否累积计算像素值的个数;
void cv::line(InputOutputArray img, Point pt1, Point pt2, const Scalar &color, int thickness=1, int lineType=LINE_8, int shift=0)
第一个参数img:要划的线所在的图像;
第二个参数pt1:直线起点
第二个参数pt2:直线终点
第三个参数color:直线的颜色 e.g:Scalor(0,0,255)
第四个参数thickness=1:线条粗细
第五个参数line_type=8,
第六个参数:坐标点的小数点位数。
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
const int bins = 256;
Mat src;
const char* winTitle = "input image";
void showHistogram();
int main(int argc, char** argv) {
src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return 0;
}
namedWindow(winTitle, WINDOW_AUTOSIZE);
imshow(winTitle, src);
showHistogram();
waitKey(0);
return 0;
}
void showHistogram()
{
vector<Mat> bgr_plane;
split(src, bgr_plane);
// split分割成bgr_plane[0], bgr_plane[1], bgr_plane[2]
const int channels[1] = { 0 };
const int bins[1] = { 256 };
float hranges[2] = { 0,255 };
const float* ranges[1] = { hranges };
Mat b_hist;
Mat g_hist;
Mat r_hist;
// calcHist函数胡 输出为b_hist
calcHist(&bgr_plane[0], 1, 0, Mat(), b_hist, 1, bins, ranges);
calcHist(&bgr_plane[1], 1, 0, Mat(), g_hist, 1, bins, ranges);
calcHist(&bgr_plane[2], 1, 0, Mat(), r_hist, 1, bins, ranges);
// 定义要画直方图的尺寸大小
int hist_w = 512;
int hist_h = 400;
int bin_w = cvRound((double)hist_w / bins[0]);
//向最近的整数取整 得到在新图横坐标单位长度
Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
//
normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
//
for (int i = 1; i < bins[0]; i++)
{
line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),
Point(bin_w * (i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0);
//绘制两个点之间的线段
line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))),
Point(bin_w * (i), hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0), 2, 8, 0);
line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))),
Point(bin_w * (i), hist_h - cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255), 2, 8, 0);
}
namedWindow("Histogram Demo", WINDOW_AUTOSIZE);
imshow("Histogram Demo", histImage);
}
输入图像
输出图像
18_图像直方图均衡化
通过图像数据的直方图,可以快速判断图像的亮度和质量。直方图均衡化就是通过图像变换使得直方图均匀分布,起到对比度增强的效果。针对离散形式的图像数据,最常用的一种方法就是累计概率分布。首先统计0-255灰度值所占像素个数;再计算出像素个数与总像素的比,表示为出现的概率;从0开始进行累计概率分布,即从0慢慢累加各层概率值直到1;则均衡化图像的灰度值=原灰度值所对应的累计概率*255。
void equalizeHist( InputArray src, OutputArray dst );
param1:InputArray src 输入图像
param2:OutputArray dst 输出图像
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int artc, char** argv) {
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
Mat gray, dst;
cvtColor(src, gray, COLOR_BGR2GRAY);
imshow("input", gray);
equalizeHist(gray, dst);
imshow("eq", dst);
waitKey(0);
return 0;
}
输入图像
输出图像1
输出图像2
19_图像直方图比较
(1)图像相似度比较
如果我们有两张图像,并且这两张图像的直方图一样,或者有极高的相似度,那么在一定程度上,我们可以认为这两幅图是一样的,这就是直方图比较的应用之一。
(2)分析图像之间关系
两张图像的直方图反映了该图像像素的分布情况,可以利用图像的直方图,来分析两张图像的关系。
HistCompMethods
HISTCMP_CORREL = 0,
HISTCMP_CHISQR = 1,
HISTCMP_INTERSECT = 2,
HISTCMP_BHATTACHARYYA = 3,
HISTCMP_CHISQR_ALT = 4,
HISTCMP_KL_DIV = 5
当method取HISTCMP_CORREL时,如果两幅图像的直方图完全一致,则计算值为1;如果两幅图像的直方图完全不相关,则计算值为0。
当method取HISTCMP_CHISQR 时,如果两幅图像的直方图完全一致,则计算值为0;两幅图像的相似性越低,计算值越大。
当method取HISTCMP_INTERSECT时,数值越大,相似性越高;数值越小,相似性越低。
当method取HISTCMP_BHATTACHARYYA 时,如果两幅图像的直方图完全一致,则计算值为0;两幅图像的相似性越低,计算值越大。
当method取HISTCMP_CHISQR_ALT 时,如果两幅图像的直方图完全一致,则计算值为0;两幅图像的相似性越低,计算值越大。
当method取HISTCMP_KL_DIV 时,如果两幅图像的直方图完全一致,则计算值为0;两幅图像的相似性越低,计算值越大。
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
}
int main(int artc, char** argv) {
Mat src1 = imread("test.png");
Mat src2 = imread("Mat.png");
Mat src3 = imread("test.png");
Mat src4 = imread("test.png");
imshow("input1", src1);
imshow("input2", src2);
imshow("input3", src3);
imshow("input4", src4);
Mat hsv1, hsv2, hsv3, hsv4;
cvtColor(src1, hsv1, COLOR_BGR2HSV);
cvtColor(src2, hsv2, COLOR_BGR2HSV);
cvtColor(src3, hsv3, COLOR_BGR2HSV);
cvtColor(src4, hsv4, COLOR_BGR2HSV);
int h_bins = 60; int s_bins = 64;
int histSize[] = { h_bins, s_bins };
float h_ranges[] = { 0, 180 };
float s_ranges[] = { 0, 256 };
const float* ranges[] = { h_ranges, s_ranges };
int channels[] = { 0, 1 };
Mat hist1, hist2, hist3, hist4;
calcHist(&hsv1, 1, channels, Mat(), hist1, 2, histSize, ranges, true, false);
calcHist(&hsv2, 1, channels, Mat(), hist2, 2, histSize, ranges, true, false);
calcHist(&hsv3, 1, channels, Mat(), hist3, 2, histSize, ranges, true, false);
calcHist(&hsv4, 1, channels, Mat(), hist4, 2, histSize, ranges, true, false);
normalize(hist1, hist1, 0, 1, NORM_MINMAX, -1, Mat());
normalize(hist2, hist2, 0, 1, NORM_MINMAX, -1, Mat());
normalize(hist3, hist3, 0, 1, NORM_MINMAX, -1, Mat());
normalize(hist4, hist4, 0, 1, NORM_MINMAX, -1, Mat());
for (int i = 0; i < 4; i++)
{
int compare_method = i;
double src1_src2 = compareHist(hist1, hist2, compare_method);
double src3_src4 = compareHist(hist3, hist4, compare_method);
printf(" Method [%d] : src1_src2 : %f, src3_src4: %f, \n", i, src1_src2, src3_src4);
}
waitKey(0);
return 0;
}
输出
20_直方图反向投影
反向投影是一种记录给定图像中的像素点如何适应直方图模型像素分布的方式,简单来讲,
反向投影就是首先计算某一特征的直方图模型,然后使用模型去寻找图像中存在的特征。反向投影在某一位置的值就是原图对应位置像素值在原图像中的总数目。
void cv::calcBackProject(
const Mat * images,
int nimages,
const int * channels,
InputArray hist,
OutputArray backProject,
const float ** ranges,
double scale = 1,
bool uniform = true
)
参数解释
//const Mat* images:输入图像,图像深度必须位CV_8U, CV_16U或CV_32F中的一种,尺寸相同,每一幅图像都可以有任意的通道数
//int nimages : 输入图像的数量
//const int channels* : 用于计算反向投影的通道列表,通道数必须与直方图维度相匹配,第一个数组的通道是从0到image[0].channels() - 1, 第二个数组通道从图像image[0].channels()到image[0].channels() + image[1].channels() - 1计数
//InputArray hist : 输入的直方图,直方图的bin可以是密集(dense)或稀疏(sparse)
//OutputArray backProject : 目标反向投影输出图像,是一个单通道图像,与原图像有相同的尺寸和深度
//const float ranges** : 直方图中每个维度bin的取值范围
//double scale = 1 : 可选输出反向投影的比例因子
//bool uniform = true : 直方图是否均匀分布(uniform)的标识符,有默认值true
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
const int bins = 256;
Mat src;
const char* winTitle = "input image";
void backProjection_demo(Mat& image, Mat& model);
int main(int argc, char** argv) {
Mat src = imread("Mat.png");
Mat model = imread("test.png");
if (src.empty() || model.empty()) {
printf("could not load image...\n");
return 0;
}
namedWindow(winTitle, WINDOW_AUTOSIZE);
imshow(winTitle, src);
imshow("model", model);
backProjection_demo(src, model);
waitKey(0);
return 0;
}
void backProjection_demo(Mat& image, Mat& model) {
Mat model_hsv, image_hsv;
cvtColor(model, model_hsv, COLOR_BGR2HSV);
cvtColor(image, image_hsv, COLOR_BGR2HSV);
//
int h_bins = 32; int s_bins = 32;
int histSize[] = { h_bins, s_bins };
// hue varies from 0 to 179, saturation from 0 to 255
float h_ranges[] = { 0, 180 };
float s_ranges[] = { 0, 256 };
const float* ranges[] = { h_ranges, s_ranges };
int channels[] = { 0, 1 };
Mat roiHist;
calcHist(&model_hsv, 1, channels, Mat(), roiHist, 2, histSize, ranges, true, false);
normalize(roiHist, roiHist, 0, 255, NORM_MINMAX, -1, Mat());
MatND backproj;
calcBackProject(&image_hsv, 1, channels, roiHist, backproj, ranges, 1.0);
imshow("BackProj", backproj);
}
输入图片
model图像
输出图片
21_卷积操作
void blur( InputArray src, OutputArray dst,
Size ksize, Point anchor = Point(-1,-1),
int borderType = BORDER_DEFAULT );
param1:输入图像
param2:输出图像
param3:卷积核的尺寸
param4:锚点,即内在哪核;锚应该位于内核内;默认值(-1,-1)表示锚点在内核中心
/** @brief Convolves an image with the kernel. 通过卷积核进行图像卷积
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int artc, char** argv) {
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
int h = src.rows;
int w = src.cols;
// 3x3
Mat dst = src.clone();
for (int row = 1; row < h - 1; row++) {
for (int col = 1; col < w - 1; col++) {
Vec3b p1 = src.at<Vec3b>(row - 1, col - 1);
Vec3b p2 = src.at<Vec3b>(row - 1, col);
Vec3b p3 = src.at<Vec3b>(row - 1, col + 1);
Vec3b p4 = src.at<Vec3b>(row, col - 1);
Vec3b p5 = src.at<Vec3b>(row, col);
Vec3b p6 = src.at<Vec3b>(row, col + 1);
Vec3b p7 = src.at<Vec3b>(row + 1, col - 1);
Vec3b p8 = src.at<Vec3b>(row + 1, col);
Vec3b p9 = src.at<Vec3b>(row + 1, col + 1);
int b = p1[0] + p2[0] + p3[0] + p4[0] + p5[0] + p6[0] + p7[0] + p8[0] + p9[0];
int g = p1[1] + p2[1] + p3[1] + p4[1] + p5[1] + p6[1] + p7[1] + p8[1] + p9[1];
int r = p1[2] + p2[2] + p3[2] + p4[2] + p5[2] + p6[2] + p7[2] + p8[2] + p9[2];
dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(b / 9);
dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(g / 9);
dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(r / 9);
}
}
imshow("blur", dst);
imwrite("D:/result.png", dst);
Mat result;
blur(src, result, Size(15, 15), Point(-1, -1), 4);
imshow("result", result);
waitKey(0);
return 0;
}
输入图像:
输出图像1:
输出图像2:
22_图像均值和高斯模糊
void GaussianBlur( InputArray src, OutputArray dst, Size ksize,
double sigmaX, double sigmaY = 0,
int borderType = BORDER_DEFAULT );
param1:输入图像 1通道或者3通道
param2:输出图像 与输入图像类型相一致的图像类型
param3:卷积核的尺寸
param4:X方向的sigma
param5:Y方向的sigma
param6:各种边界类型,图像边界用。一般不研究
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int artc, char** argv) {
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
Mat dst1, dst2;
//卷积
blur(src, dst1, Size(5, 5), Point(-1, -1), 4);
//高斯模糊
GaussianBlur(src, dst2, Size(5, 5), 15, 0, 4);
imshow("blur", dst1);
imshow("gaussian blur", dst2);
waitKey(0);
return 0;
}
输入图像:
输出图像1:
输出图像2:
23_中值滤波
void medianBlur( InputArray src, OutputArray dst, int ksize );
param1:输入图像 1通道或者3通道
param2:输出图像 与输入图像类型相一致的图像类型
param3:卷积核的尺寸
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int artc, char** argv) {
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
Mat dst;
medianBlur(src, dst, 5);
imshow("medianblur ksize=5", dst);
waitKey(0);
return 0;
}
输入图像:
输出图像:
24_图像噪声
RNG rng(12345);//随机数生成器
cv::RNG 可以产生3种随机数。
(1)RNG(int seed) 使用种子seed产生一个64位随机整数,默认-1。
(2)cv::RNG::uniform( ) 产生一个均匀分布的随机数。
(3)cv::RNG::gaussian( ) 产生一个高斯分布的随机数。
void add(InputArray src1, InputArray src2, OutputArray dst,
InputArray mask = noArray(), int dtype = -1);
param1:第一输入数组或标量
param2:第e二输入数组或标量
param3:输出数组或标量
void randn(InputOutputArray dst, InputArray mean, InputArray stddev); // 用于生产正态分布的随机数。
param1: 随机数的输出对象;必须预先定义好大小。
param2: 随机数的平均值。
param3: 随机数的标准偏差。
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
void add_salt_pepper_noise(Mat& image);
void gaussian_noise(Mat& image);
int main(int artc, char** argv) {
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
gaussian_noise(src);
waitKey(0);
return 0;
}
void add_salt_pepper_noise(Mat& image) {
RNG rng(12345);
int h = image.rows;
int w = image.cols;
int nums = 10000;
for (int i = 0; i < nums; i++) {
int x = rng.uniform(0, w);
int y = rng.uniform(0, h);
if (i % 2 == 1) {
image.at<Vec3b>(y, x) = Vec3b(255, 255, 255);
}
else {
image.at<Vec3b>(y, x) = Vec3b(0, 0, 0);
}
}
imshow("salt pepper", image);
}
void gaussian_noise(Mat& image) {
Mat noise = Mat::zeros(image.size(), image.type());
randn(noise, (15, 15, 15), (30, 30, 30));
Mat dst;
add(image, noise, dst);
imshow("gaussian noise", dst);
}
输入图片:
输出图片:
25_图像去噪声
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
void add_salt_pepper_noise(Mat& image);
void gaussian_noise(Mat& image);
int main(int artc, char** argv) {
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
gaussian_noise(src);
Mat result1, result2, result3, result4;
blur(src, result1, Size(5, 5));
imshow("result-1", result1);
GaussianBlur(src, result2, Size(5, 5), 0);
imshow("result-2", result2);
medianBlur(src, result3, 5);
imshow("result-3", result3);
fastNlMeansDenoisingColored(src, result4, 15, 15, 10, 30);
imshow("result-4", result4);
waitKey(0);
return 0;
}
void add_salt_pepper_noise(Mat& image) {
RNG rng(12345);
int h = image.rows;
int w = image.cols;
int nums = 10000;
for (int i = 0; i < nums; i++) {
int x = rng.uniform(0, w);
int y = rng.uniform(0, h);
if (i % 2 == 1) {
image.at<Vec3b>(y, x) = Vec3b(255, 255, 255);
}
else {
image.at<Vec3b>(y, x) = Vec3b(0, 0, 0);
}
}
imshow("salt pepper", image);
}
void gaussian_noise(Mat& image) {
Mat noise = Mat::zeros(image.size(), image.type());
randn(noise, (15, 15, 15), (30, 30, 30));
Mat dst;
add(image, noise, dst);
imshow("gaussian noise", dst);
dst.copyTo(image);
}
输入图像:
输出图像1:
输出图像2:
输出图像3:
输出图像4:
输出图像5:
26_双边滤波
滤波方法都会对图像造成模糊,使得边缘信息变弱或者消失,而双边滤波是综合考虑空间信息和
色彩信息的滤波方式,在滤波过程中能够有效地保护图像内的边缘信息。
dst=cv2.bilateralFilter(src,d,sigmaColor,sigmaSpace,borderType)
● dst是返回值,表示进行双边滤波后得到的处理结果。
● src 是需要处理的图像,即原始图像。它能够有任意数量的通道,并能对各通道独立处理。图像深度应该是CV_8U、CV_16U、CV_16S、CV_32F或者CV_64F中的一 种。
● d是在滤波时选取的空间距离参数,这里表示以当前像素点为中心点的直径。如果该值为非正数,则会自动从参数 sigmaSpace 计算得到。如果滤波空间较大(d>5),则速度较慢。因此,在实时应用中,推荐d=5。对于较大噪声的离线滤波,可以选择d=9。
● sigmaColor是滤波处理时选取的颜色差值范围,该值决定了周围哪些像素点能够参与到滤波中来。与当前像素点的像素值差值小于 sigmaColor 的像素点,能够参与到当前的滤波中。该值越大,就说明周围有越多的像素点可以参与到运算中。该值为0时,滤波失去意义;该值为255时,指定直径内的所有点都能够参与运算。
● sigmaSpace是坐标空间中的sigma值。它的值越大,说明有越多的点能够参与到滤波计算中来。当d>0时,无论sigmaSpace的值如何,d都指定邻域大小;否则,d与 sigmaSpace的值成比例。
● borderType是边界样式,该值决定了以何种方式处理边界。一般情况下,不需要考虑该值,直接采用默认值即可。
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int artc, char** argv) {
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
Mat dst;
bilateralFilter(src, dst, 0, 100, 10, 4);
imshow("result", dst);
waitKey(0);
return 0;
}
输入图像:
输出图像:
27_均值偏移滤波
cv.pyrMeanShiftFiltering()
对图像进行均值偏移滤波,这个函数作用是图像在色彩层面的平滑滤波,它可以中和色彩分布相近的颜色,
平滑色彩细节,侵蚀掉面积较小的颜色区域,函数的输出是一个“色调分离”的新图像,意味着去除了精细
纹理、颜色梯度大部分变得平坦。
pyrMeanShiftFiltering( InputArray src, OutputArray dst,double sp,
double sr, int maxLevel=1,termcrit);
param1:scr 输入图像,8位,三通道的彩色图像
param2:dst 输出图像,跟输入src有同样的大小和数据格式
param3:sp 定义的偏移物理空间半径大小
param4:sr 定义的偏移色彩空间半径大小
param5:maxLevel 定义金字塔的最大层数
param6:termcrit 定义的漂移迭代终止条件
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int artc, char** argv) {
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
Mat dst;
pyrMeanShiftFiltering(src, dst, 15, 50, 1, TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 5, 1));
imshow("result", dst);
waitKey(0);
return 0;
}
输入图像:
输出图像:
28_图像积分图算法
1、图像积分图算法:
积分图像是Crow在1984年首次提出,是为了在多尺度透视投影中提高渲染速度,是一种快速计算图像
矩形区域和与矩形区域平方和的算法。这种算法的主要优点是一旦积分图像首先被计算出来,我们就可
以在常量时间内计算图像中任意大小矩形区域的和。这样在图像模糊、边缘提取、对象检测的时候极大
降低计算量、提高计算速度。
2、作用:
当需要多次重复对像素值进行计算时,利用积分图可以大大减少计算量、提高计算速度。
3、什么是积分图:
图像是由一系列的离散像素点组成,因此图像的积分其实就是求和。【图像积分图中每个点的值是原图
像中该点左上角的所有像素值之和。】积分图中任意一点(x,y)的值等于灰度图的左上角与当前点所
围成的矩形区域内所有像素点灰度值之和。
void integral( InputArray src, OutputArray sum,OutputArray sqsum, int sdepth = -1,
int sqdepth = -1 );
param1: src:输入图像。
param2: sum:和表。
param3: sqsum:平方和表。
param4: tilted:瓦块和表。
param5: sdepth : 默认值-1。和表数据深度常见CV_32S。
param6: sqdepth: 默认值 -1。平方和表数据深度常见 CV_32F。
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
void blur_demo(Mat& image, Mat& sum);
void edge_demo(Mat& image, Mat& sum);
int getblockSum(Mat& sum, int x1, int y1, int x2, int y2, int i);
int main(int argc, char** argv) {
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
namedWindow("output", WINDOW_AUTOSIZE);
Mat sum, sqrsum;
integral(src, sum, sqrsum, CV_32S, CV_32F);
int type = 0;
while (true) {
char c = waitKey(100);
if (c > 0) {
type = (int)c;
printf("c : %d\n", type);
}
if (c == 27) {
break; // ESC
}
if (type == 49) {
blur_demo(src, sum);
}
else if (type == 50) {
edge_demo(src, sum);
}
else {
blur_demo(src, sum);
}
}
waitKey(0);
return 0;
}
void blur_demo(Mat& image, Mat& sum) {
int w = image.cols;
int h = image.rows;
Mat result = Mat::zeros(image.size(), image.type());
int x2 = 0, y2 = 0;
int x1 = 0, y1 = 0;
int ksize = 5;
int radius = ksize / 2;
int ch = image.channels();
int cx = 0, cy = 0;
for (int row = 0; row < h + radius; row++) {
y2 = (row + 1) > h ? h : (row + 1);
y1 = (row - ksize) < 0 ? 0 : (row - ksize);
for (int col = 0; col < w + radius; col++) {
x2 = (col + 1) > w ? w : (col + 1);
x1 = (col - ksize) < 0 ? 0 : (col - ksize);
cx = (col - radius) < 0 ? 0 : col - radius;
cy = (row - radius) < 0 ? 0 : row - radius;
int num = (x2 - x1) * (y2 - y1);
for (int i = 0; i < ch; i++) {
int s = getblockSum(sum, x1, y1, x2, y2, i);
result.at<Vec3b>(cy, cx)[i] = saturate_cast<uchar>(s / num);
}
}
}
imshow("output", result);
}
/**
* 3x3 sobel
*/
void edge_demo(Mat& image, Mat& sum) {
int w = image.cols;
int h = image.rows;
Mat result = Mat::zeros(image.size(), CV_32SC3);
int x2 = 0, y2 = 0;
int x1 = 0, y1 = 0;
int ksize = 3;
int radius = ksize / 2;
int ch = image.channels();
int cx = 0, cy = 0;
for (int row = 0; row < h + radius; row++) {
y2 = (row + 1) > h ? h : (row + 1);
y1 = (row - ksize) < 0 ? 0 : (row - ksize);
for (int col = 0; col < w + radius; col++) {
x2 = (col + 1) > w ? w : (col + 1);
x1 = (col - ksize) < 0 ? 0 : (col - ksize);
cx = (col - radius) < 0 ? 0 : col - radius;
cy = (row - radius) < 0 ? 0 : row - radius;
int num = (x2 - x1) * (y2 - y1);
for (int i = 0; i < ch; i++) {
int s1 = getblockSum(sum, x1, y1, cx, y2, i);
int s2 = getblockSum(sum, cx, y1, x2, y2, i);
result.at<Vec3i>(cy, cx)[i] = saturate_cast<int>(s2 - s1);
}
}
}
Mat dst, gray;
convertScaleAbs(result, dst);
normalize(dst, dst, 0, 255, NORM_MINMAX);
cvtColor(dst, gray, COLOR_BGR2GRAY);
imshow("output", gray);
}
int getblockSum(Mat& sum, int x1, int y1, int x2, int y2, int i) {
int tl = sum.at<Vec3i>(y1, x1)[i];
int tr = sum.at<Vec3i>(y2, x1)[i];
int bl = sum.at<Vec3i>(y1, x2)[i];
int br = sum.at<Vec3i>(y2, x2)[i];
int s = (br - bl - tr + tl);
return s;
}
29_快速的图像边缘滤波算法(边缘保护滤波)
/**
* @brief getTickCount() 该函数返回CPU自某个事件以来走过的时钟周期数
* @brief getTickFrequency() 该函数返回CPU一秒钟所走的时钟周期数。便于以秒为单位进行计时。
*/
// 计时开始
double timex = static_cast<double>(getTickCount());
// 需要计时的函数或代码
..............
// 计时结束
timex = ((double)getTickCount() - timex) / getTickFrequency();//能得到走了多少秒
// 时间输出
cout << "运行时间为:" << timex << "秒" << endl ;
void edgePreservingFilter( InputArray src, OutputArray dst, int flags = 1,
float sigma_s = 60, float sigma_r = 0.4f);//边缘保护滤波
src: 输入 8 位 3 通道图像。
dst: 输出 8 位 3 通道图像。
flags: 边缘保护滤波 cv::RECURS_FILTER 或 cv::NORMCONV_FILTER。
flags在枚举中取 enum
{
RECURS_FILTER = 1, // Recursive Filtering
NORMCONV_FILTER = 2 // Normalized Convolution Filtering
};
sigma_s:取值范围为 0~200。
sigma_r:取值范围为 0~1。
当sigma_s 取值不变时候,sigma_r 越大图像滤波效果越明显;
当sigma_r 取值不变时候,窗口 sigma_s 越大图像模糊效果越明显;
当sgma_r取值很小的时候,窗口 sigma_s 取值无论如何变化,图像双边滤波效果都不好
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int artc, char** argv) {
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
Mat dst;
double tt = getTickCount();
edgePreservingFilter(src, dst, 1, 60, 0.44);
double end = (getTickCount() - tt) / getTickFrequency();
printf("time consume : %f\n ", end);
imshow("result", dst);
waitKey(0);
return 0;
}
输入图像:
输出图像:
30_自定义滤波器
允许用户自定义卷积核实现卷积操作,使用自定义卷积核实现卷积操作的函数是cv2.filter2D(),其语法格式为:
dst=cv2.filter2D(src,ddepth,kernel,anchor,delta,borderType)
● dst是返回值,表示进行方框滤波后得到的处理结果。
● src 是需要处理的图像,即原始图像。它能够有任意数量的通道,并能对各个通道独立处理。图像深度应该是CV_8U、CV_16U、CV_16S、CV_32F或者CV_64F中的一 种。
● ddepth是处理结果图像的图像深度,一般使用-1表示与原始图像使用相同的图像深度。
● kernel是卷积核,是一个单通道的数组。如果想在处理彩色图像时,让每个通道使用不同的核,则必须将彩色图像分解后使用不同的核完成操作。
● anchor 是锚点,其默认值是(-1,-1),表示当前计算均值的点位于核的中心点位 置。该值使用默认值即可,在特殊情况下可以指定不同的点作为锚点。
● delta 是修正值,它是可选项。如果该值存在,会在基础滤波的结果上加上该值作 为最终的滤波处理结果。
● borderType是边界样式,该值决定了以何种情况处理边界,通常使用默认值即可。
在一般情况下,使用cv.filter2D()时,对于参数锚点anchor,修正值delta,边界样式borderType,直接采用其默认值即可。因此,cv.filter2D()的常用形式为:dst=cv2.filter2D(src,ddepth,kernel)
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int artc, char** argv) {
Mat src = imread("./test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", CV_WINDOW_AUTOSIZE);
imshow("input", src);
Mat kernel1 = Mat::ones(5, 5, CV_32F) / (float)(25);
Mat kernel2 = (Mat_<char>(3, 3) << 0, -1, 0,
-1, 5, -1,
0, -1, 0);
Mat kernel3 = (Mat_<int>(2, 2) << 1, 0, 0, -1);
Mat dst1, dst2, dst3;
filter2D(src, dst1, -1, kernel1);
filter2D(src, dst2, -1, kernel2);
filter2D(src, dst3, CV_32F, kernel3);
convertScaleAbs(dst3, dst3);
imshow("blur=5x5", dst1);
imshow("shape=3x3", dst2);
imshow("gradient=2x2", dst3);
waitKey(0);
return 0;
}
输入图像:
输出图像1:
输出图像2:
输出图像3:
31_Sobel算子
void Sobel( InputArray src, OutputArray dst, int ddepth,
int dx, int dy, int ksize = 3,
double scale = 1, double delta = 0,
int borderType = BORDER_DEFAULT );
param1:输入图像
param2:输出图像
param3:图像的深度
param4:x方向
param5:Y方向
param6:sobel核的大小 必须为3
void cv::convertScaleAbs(
cv::InputArray src, // 输入数组
cv::OutputArray dst, // 输出数组
double alpha = 1.0, // 乘数因子
double beta = 0.0 // 偏移量
);
cv::convertScaleAbs()用于实现对整个图像数组中的每一个元素
d
s
t
i
=
s
a
t
u
r
a
t
e
(
α
∗
s
r
c
i
+
β
)
dst_i=saturate(\alpha*src_i+\beta)
dsti=saturate(α∗srci+β)
该操作可实现图像增强等相关操作的快速运算
void cv::convertScaleAbs(
cv::InputArray src, // 输入数组
cv::OutputArray dst, // 输出数组
double alpha = 1.0, // 乘数因子
double beta = 0.0 // 偏移量
);
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int artc, char** argv) {
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
Mat grad_x, grad_y;
Mat dst;
Sobel(src, grad_x, CV_32F, 1, 0, 3, 1, 0, BORDER_DEFAULT);
Sobel(src, grad_y, CV_32F, 0, 1, 3, 1, 0, BORDER_DEFAULT);
convertScaleAbs(grad_x, grad_x);
convertScaleAbs(grad_y, grad_y);
add(grad_x, grad_y, dst, Mat(), CV_16S);
convertScaleAbs(dst, dst);
imshow("gradient", dst);
waitKey(0);
return 0;
}
输入图像:
输出图像:
32_梯度算子
robert算子
prewitt算子
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int artc, char** argv) {
Mat src = imread("./test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", CV_WINDOW_AUTOSIZE);
imshow("input", src);
Mat robert_x = (Mat_<int>(2, 2) << 1, 0, 0, -1);
Mat robert_y = (Mat_<int>(2, 2) << 0, -1, 1, 0);
Mat prewitt_x = (Mat_<char>(3, 3) << -1, 0, 1,
-1, 0, 1,
-1, 0, 1);
Mat prewitt_y = (Mat_<char>(3, 3) << -1, -1, -1,
0, 0, 0,
1, 1, 1);
Mat robert_grad_x, robert_grad_y, prewitt_grad_x, prewitt_grad_y;
filter2D(src, robert_grad_x, CV_16S, robert_x);
filter2D(src, robert_grad_y, CV_16S, robert_y);
convertScaleAbs(robert_grad_x, robert_grad_x);
convertScaleAbs(robert_grad_y, robert_grad_y);
filter2D(src, prewitt_grad_x, CV_32F, prewitt_x);
filter2D(src, prewitt_grad_y, CV_32F, prewitt_y);
convertScaleAbs(prewitt_grad_x, prewitt_grad_x);
convertScaleAbs(prewitt_grad_y, prewitt_grad_y);
printf("image gradient...");
imshow("robert x", robert_grad_x);
imshow("robert y", robert_grad_y);
imshow("prewitt x", prewitt_grad_x);
imshow("prewitt y", prewitt_grad_y);
waitKey(0);
return 0;
}
输入图像:
输出图像1:
输出图像2:
输出图像3:
输出图像4:
33_拉普拉斯算子
void GaussianBlur( InputArray src, OutputArray dst, Size ksize,
double sigmaX, double sigmaY = 0,
int borderType = BORDER_DEFAULT );
参数说明
InputArray类型的src,输入图像,如Mat类型。
OutputArray类型的dst,输出图像。
Size类型的ksize,高斯内核的大小。
double类型的sigmaX,高斯核函数在X方向的标准偏差。
double类型的sigmaY,高斯核函数在Y方向的标准偏差。
int类型的borderType,推断图像边缘像素的边界模式。
void Laplacian( InputArray src, OutputArray dst, int ddepth,
int ksize = 1, double scale = 1, double delta = 0,
int borderType = BORDER_DEFAULT );
param1:输入图像
param2:输出图像
param3:图像的深度
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int artc, char** argv) {
Mat image = imread("./test.png");
if (image.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", CV_WINDOW_AUTOSIZE);
imshow("input", image);
Mat blured, dst;
GaussianBlur(image, blured, Size(3, 3), 0);
Laplacian(blured, dst, CV_32F, 1, 1.0, 127.0, BORDER_DEFAULT);
convertScaleAbs(dst, dst);
imshow("result", dst);
waitKey(0);
return 0;
}
输入图像:
输出图像:
34_图像的锐化
采用自定义滤波进行锐化
Mat_<char>(3, 3) << 0, -1, 0,
-1, 5, -1,
0, -1, 0);
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int artc, char** argv) {
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
Mat sharpen_op = (Mat_<char>(3, 3) << 0, -1, 0,
-1, 5, -1,
0, -1, 0);
Mat result;
filter2D(src, result, CV_32F, sharpen_op);
convertScaleAbs(result, result);
imshow("sharpen image", result);
waitKey(0);
return 0;
}
输入图像:
输出图像:
35_USM锐化增强算法
addWeighted()函数
addWeighted()函数:用来将两个图片进行融合。
dst = cv.addWeighted( src1, alpha, src2, beta,gamma, dst, dtype)
src1:插入的第一个图片;
src2:插入的第二个图片;
alpha:double类型,加权系数,是src1图片的融合占比 ;
beta:double类型,加权系数,是src2图片的融合占比;
gamma:double类型,加权后图像的偏移量;
dst:输出图像;
dtype:默认为-1。
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int artc, char** argv) {
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
Mat blur_img, usm;
GaussianBlur(src, blur_img, Size(0, 0), 25);
addWeighted(src, 1.5, blur_img, -0.5, 0, usm);
imshow("mask image", usm);
waitKey(0);
return 0;
}
输入图像:
输出图像:
36_Canny边缘检测器
功能:
用于对图像的边缘检测
函数形式:
void Canny( InputArray image, OutputArray edges,
double threshold1, double threshold2,
int apertureSize = 3, bool L2gradient = false );
param1:输入图像
param2:输出图像(即边缘)
param3:第一个阈值
param4:第二个阈值
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int artc, char** argv) {
Mat src = imread("./test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", CV_WINDOW_AUTOSIZE);
imshow("input", src);
Mat edges;
Canny(src, edges, 100, 300, 3, false);
imshow("edge image", edges);
waitKey(0);
return 0;
}
输入图像:
输出图像:
37_图像金字塔
void pyrDown( InputArray src, OutputArray dst,const Size& dstsize = Size(),
int borderType = BORDER_DEFAULT );
param1:输入图像
param2:输出图像
param3:输出图像的尺寸。通常Size(src.cols\*2, (src.rows\*2)
param4:边界类型
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
void pyramid_up(Mat& image, vector<Mat>& pyramid_images, int level);
void pyramid_down(vector<Mat>& pyramid_images);
int main(int artc, char** argv) {
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
vector<Mat> p_images;
pyramid_up(src, p_images, 3);
pyramid_down(p_images);
waitKey(0);
return 0;
}
void pyramid_up(Mat& image, vector<Mat>& pyramid_images, int level) {
Mat temp = image.clone();
Mat dst;
for (int i = 0; i < level; i++) {
pyrDown(temp, dst);
//imshow(format("pyramid_up_%d", i), dst);
temp = dst.clone();
pyramid_images.push_back(temp);
}
}
void pyramid_down(vector<Mat>& pyramid_images) {
for (int t = pyramid_images.size() - 1; t > -1; t--) {
Mat dst;
pyrUp(pyramid_images[t], dst);
imshow(format("pyramid_down_%d", t), dst);
}
}
输入图像:
输出图像:
输出图像2:
输出图像3:
38_拉普拉斯金字塔
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
void pyramid_up(Mat &image, vector<Mat> &pyramid_images, int level);
void laplaian_demo(vector<Mat> &pyramid_images, Mat &image);
int main(int artc, char** argv) {
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", CV_WINDOW_AUTOSIZE);
imshow("input", src);
vector<Mat> p_images;
pyramid_up(src, p_images, 3);
laplaian_demo(p_images, src);
waitKey(0);
return 0;
}
void pyramid_up(Mat &image, vector<Mat> &pyramid_images, int level) {
Mat temp = image.clone();
Mat dst;
for (int i = 0; i < level; i++) {
pyrDown(temp, dst);
//imshow(format("pyramid_up_%d", i), dst);
temp = dst.clone();
pyramid_images.push_back(temp);
}
}
void laplaian_demo(vector<Mat> &pyramid_images, Mat &image) {
for (int t = pyramid_images.size() - 1; t>-1; t--) {
Mat dst;
if (t - 1 < 0) {
pyrUp(pyramid_images[t], dst, image.size());
subtract(image, dst, dst);
dst = dst + Scalar(127, 127, 127);
imshow(format("laplaian_layer_%d", t), dst);
}
else {
pyrUp(pyramid_images[t], dst, pyramid_images[t-1].size());
subtract(pyramid_images[t - 1], dst, dst);
dst = dst + Scalar(127, 127, 127);
imshow(format("laplaian_layer_%d", t), dst);
}
}
}
输入图像:
输出图像1:
输出图像2:
输出图像3:
39_图像模板匹配
void cv::matchTemplate(
cv::InputArray image, // 用于搜索的输入图像, 8U 或 32F, 大小 W-H
cv::InputArray templ, // 用于匹配的模板,和image类型相同, 大小 w-h
cv::OutputArray result, // 匹配结果图像, 类型 32F, 大小 (W-w+1)-(H-h+1)
int method // 用于比较的方法
);
1、cv::TM_SQDIFF:该方法使用平方差进行匹配,因此最佳的匹配结果在结果为0处,值越大匹配结果越差。
2、cv::TM_SQDIFF_NORMED:该方法使用归一化的平方差进行匹配,最佳匹配也在结果为0处。
3、cv::TM_CCORR:相关性匹配方法,该方法使用源图像与模板图像的卷积结果进行匹配,因此,最佳匹配位置在值最大处,值越小匹配结果越差。
4、cv::TM_CCORR_NORMED:归一化的相关性匹配方法,与相关性匹配方法类似,最佳匹配位置也是在值最大处。
5、cv::TM_CCOEFF:相关性系数匹配方法,该方法使用源图像与其均值的差、模板与其均值的差二者之间的相关性进行匹配,最佳匹配结果在值等于1处,最差匹配结果在值等于-1处,值等于0直接表示二者不相关。
6、cv::TM_CCOEFF_NORMED:归一化的相关性系数匹配方法,正值表示匹配的结果较好,负值则表示匹配的效果较差,也是值越大,匹配效果也好。
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
const float t = 0.95;
int main(int artc, char** argv) {
Mat src = imread("./test01.png");
Mat tpl = imread("./test.png");
if (src.empty() || tpl.empty()) {
printf("could not load image...\n");
return -1;
}
imshow("input", src);
imshow("tpl", tpl);
int result_h = src.rows - tpl.rows + 1;
int result_w = src.cols - tpl.cols + 1;
Mat result = Mat::zeros(Size(result_w, result_h), CV_32FC1);
matchTemplate(src, tpl, result, TM_CCOEFF_NORMED);
imshow("result image", result);
int h = result.rows;
int w = result.cols;
for (int row = 0; row < h; row++) {
for (int col = 0; col < w; col++) {
float v = result.at<float>(row, col);
// printf("v = %.2f\n", v);
if (v > t) {
rectangle(src, Point(col, row), Point(col + tpl.cols, row + tpl.rows), Scalar(255, 0, 0), 1, 8, 0);
}
}
}
imshow("template matched result", src);
waitKey(0);
return 0;
}
40_二值化图像
在这里插入代码片
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int artc, char** argv) {
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
int t = 127;
Mat gray, binary;
cvtColor(src, gray, COLOR_BGR2GRAY);
Scalar m = mean(src);
t = m[0];
binary = Mat::zeros(src.size(), CV_8UC1);
int height = src.rows;
int width = src.cols;
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
int pv = gray.at<uchar>(row, col);
if (pv > t) {
binary.at<uchar>(row, col) = 255;
}
else {
binary.at<uchar>(row, col) = 0;
}
}
}
imshow("binary", binary);
waitKey(0);
return 0;
}
输入图像:
输出图像:
41_基本阈值操作
double threshold( InputArray src, OutputArray dst,
double thresh, double maxval, int type );
src:源图像,可以为8位的灰度图,也可以为32位的彩色图像。(两者由区别)
dst:输出图像
thresh:阈值
maxval:dst图像中最大值
type:阈值类型,可以具体类型如下: (详细可查看相关类型代表的含义)
1 THRESH_BINARY
2 THRESH_BINARY_INV
3 THRESH_TRUNC
4 THRESH_TOZERO
5 THRESH_TOZERO_INV
6 THRESH_MASK
7 THRESH_OTSU
8 THRESH_TRIANGLE
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, const char* argv[])
{
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
int T = 127;
Mat gray, binary;
cvtColor(src, gray, COLOR_BGR2GRAY);
for (int i = 0; i < 5; i++) {
threshold(gray, binary, T, 255, i);
imshow(format("binary_%d", i), binary);
imwrite(format("./binary_%d.png", i), binary);
}
waitKey(0);
return 0;
}
输入图像;
输出图像1:
输出图像2:
输出图像3:
输出图像4:
输出图像5:
42_二值寻找算法(OTUS)
THRESH_OTSU
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, const char* argv[])
{
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
Mat gray, binary;
cvtColor(src, gray, COLOR_BGR2GRAY);
double t = threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
printf("threshold : %.2f\n", t);
imshow("binary", binary);
imwrite("./binary.png", binary);
waitKey(0);
return 0;
}
输入图像:
输出图像:
43_二值寻找算法TRIANGLE
THRESH_TRIANGLE
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, const char* argv[])
{
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
Mat gray, binary;
cvtColor(src, gray, COLOR_BGR2GRAY);
double t = threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_TRIANGLE);
printf("threshold : %.2f\n", t);
imshow("binary", binary);
imwrite("./binary.png", binary);
waitKey(0);
return 0;
}
输入图像:
输出图像:
44_自适应阈值
void adaptiveThreshold( InputArray src, OutputArray dst,
double maxValue, int adaptiveMethod,
int thresholdType, int blockSize, double C );
src:输入8位单通道图像。
dst:输出图像,大小和类型与src相同。
maxValue:满足条件的像素所分配的非零值。
adaptiveMethod:要使用的自适应阈值算法,ADAPTIVE_THRESH_MEAN_C或者
ADAPTIVE_THRESH_GAUSSIAN_C
thresholdType:阈值类型,必须是THRESH_BINARY或者HRESH_BINARY_INV,指要提取亮区域还是暗区域
blockSize:用于计算像素阈值的像素邻域的大小:3,5,7,以此类推。
C:偏移值调整量,从每个邻域计算出的平均值或高斯加权平均值中减去的常量,就是最终阈值,
它可以是正的,也可以是零或负的。
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, const char* argv[])
{
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
Mat gray, binary;
cvtColor(src, gray, COLOR_BGR2GRAY);
adaptiveThreshold(gray, binary, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 25, 10);
imshow("binary", binary);
imwrite("./test.png", binary);
waitKey(0);
return 0;
}
输入图像:
输出图像:
45_二值化和去噪(图像均值迁移模糊)
图像均值迁移模糊:pyrMeanShiftFiltering()
void pyrMeanShiftFiltering(
InputArray src, OutputArray dst,double sp, double sr, int maxLevel = 1,
TermCriteria termcrit=TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS,5,1) );
第1个参数 src:输入图像,8位,三通道的彩色图像,并不要求必须是RGB格式,HSV、YUV等Opencv中的
彩色图像格式均可。
第2个参数 dst:输出图像,跟输入src有同样的大小和数据格式。
第3个参数 sp,定义的漂移物理空间半径大小。
第4个参数 sr:定义的漂移色彩空间半径大小。
第5个参数 maxLevel:定义金字塔的最大层数。
第6个参数 termcrit:定义的漂移迭代终止条件,可以设置为迭代次数满足终止,迭代目标与中心点偏差满足终止,或者两者的结合。
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, const char* argv[])
{
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
Mat dst, gray, binary;
pyrMeanShiftFiltering(src, dst, 10, 100);
// GaussianBlur(src, dst, Size(3, 3), 0, 0);
cvtColor(dst, gray, COLOR_BGR2GRAY);
threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
imshow("binary", binary);
imwrite("./binary.png", binary);
waitKey(0);
return 0;
}
输入图像:
输出图像:
46_连通域分析查找
int cv::connectedComponents (
cv::InputArrayn image, // //8位单通道二值图像 (binary)
cv::OutputArray labels, // output label map //和原图一样大的标记图
int connectivity = 8, // 4- or 8-connected components
int ltype = CV_32S // Output label type (CV_32S or CV_16U)
);
int cv::connectedComponentsWithStats (
cv::InputArrayn image,
// input 8-bit single-channel (binary)
cv::OutputArray labels,
// output label map
cv::OutputArray stats,
// Nx5 matrix (CV_32S) of statistics:
// [x0, y0, width0, height0, area0;//nccomps×5的矩阵 表示每个连通区域的外接矩形和面积(pixel)
// ... ; x(N-1), y(N-1), width(N-1), height(N-1), area(N-1)]
cv::OutputArray centroids,
//nccomps×2的矩阵 表示每个连通区域的质心(pixel)Nx2 CV_64F matrix of centroids: [ cx0, cy0; ... ; cx(N-1), cy(N-1)]
int connectivity = 8,
// 4- or 8-connected components
int ltype = CV_32S
// Output label type (CV_32S or CV_16U)
);
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
RNG rng(12345);
void connected_component_demo(Mat& image);
int main(int argc, char** argv) {
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
}
imshow("input", src);
connected_component_demo(src);
waitKey(0);
return 0;
}
void connected_component_demo(Mat& image) {
//提取特征
Mat gray, binary;
GaussianBlur(image, image, Size(3, 3), 0);
cvtColor(image, gray, COLOR_BGR2GRAY);
threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
Mat labels = Mat::zeros(image.size(), CV_32S);
int num_labels = connectedComponents(binary, labels, 8, CV_32S);
printf("total labels : %d\n", (num_labels - 1));
vector<Vec3b> colors(num_labels);
//背景颜色
colors[0] = Vec3b(0, 0, 0);
for (int i = 1; i < num_labels; i++) {
colors[i] = Vec3b(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));
}
Mat dst = Mat::zeros(image.size(), image.type());
int w = image.cols;
int h = image.rows;
for (int row = 0; row < h; row++) {
for (int col = 0; col < w; col++) {
int label = labels.at<int>(row, col);
if (label == 0) continue;
dst.at<Vec3b>(row, col) = colors[label];
}
}
imshow("ccla-demo", dst);
imwrite("./ccla_dst.png", dst);
}
输入图像:
输出图像:
47_连通域状态统计
int cv::connectedComponents (
cv::InputArrayn image,
// input 8-bit single-channel (binary)
cv::OutputArray labels,
// output label map
int connectivity = 8,
// 4- or 8-connected components
int ltype = CV_32S
// Output label type (CV_32S or CV_16U)
);
int cv::connectedComponentsWithStats (
cv::InputArrayn image, // input 8-bit single-channel (binary)
cv::OutputArray labels, // output label map
cv::OutputArray stats, // Nx5 matrix (CV_32S) of statistics:
// [x0, y0, width0, height0, area0;
// ... ; x(N-1), y(N-1), width(N-1),
// height(N-1), area(N-1)]
cv::OutputArray centroids, // Nx2 CV_64F matrix of centroids:
// [ cx0, cy0; ... ; cx(N-1), cy(N-1)]
int connectivity = 8, // 4- or 8-connected components
int ltype = CV_32S // Output label type (CV_32S or CV_16U)
);
//connectedComponentsWithStats()函数原理是检测像素的连通区域
void putText( InputOutputArray img, const String& text, Point org,
int fontFace, double fontScale, Scalar color,
int thickness = 1, int lineType = LINE_8,
bool bottomLeftOrigin = false );
InputOutputArray类型的img,输入图像也是输出图像,如Mat类型。
const String&类型的text,所要绘制的文字。
Point类型的org,文字的位置,第一个数值表示文字最左侧的位置,第二个数值表示文字居中线距离图像的长度。
int类型的fontFace,文字字体。
double类型的fontScale,文字大小。
Scalar类型的color,文字颜色。
int类型的thickness,文字线条宽度。
int类型的line_type,绘制线的类型,-1就是FILLED(填满),4是LINE_4(4连通域),8是LINE_8(8连通域),LINE_AA(抗锯齿线)。
bool类型的bottomLeftOrigin,标识原点位置,若为true,则表示图像左下角为原点,OpenCV中原点位置一般为左上角。
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
RNG rng(12345);
void componentwithstats_demo(Mat& image);
int main(int argc, char** argv) {
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
}
imshow("input", src);
componentwithstats_demo(src);
waitKey(0);
return 0;
}
void componentwithstats_demo(Mat& image) {
Mat gray, binary;
GaussianBlur(image, image, Size(3, 3), 0);
cvtColor(image, gray, COLOR_BGR2GRAY);
threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
Mat labels = Mat::zeros(image.size(), CV_32S);
Mat stats, centroids;
int num_labels = connectedComponentsWithStats(binary, labels, stats, centroids, 8, 4);
printf("total labels : %d\n", (num_labels - 1));
vector<Vec3b> colors(num_labels);
colors[0] = Vec3b(0, 0, 0);
for (int i = 1; i < num_labels; i++) {
colors[i] = Vec3b(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));
}
Mat dst = image.clone();
int w = image.cols;
int h = image.rows;
for (int i = 1; i < num_labels; i++) {
int cx = centroids.at<double>(i, 0);
int cy = centroids.at<double>(i, 1);
int x = stats.at<int>(i, CC_STAT_LEFT);
int y = stats.at<int>(i, CC_STAT_TOP);
int w = stats.at<int>(i, CC_STAT_WIDTH);
int h = stats.at<int>(i, CC_STAT_HEIGHT);
int area = stats.at<int>(i, CC_STAT_AREA);
circle(dst, Point(cx, cy), 2, Scalar(0, 255, 0), 2, 8, 0);
Rect rect(x, y, w, h);
rectangle(dst, rect, colors[i], 1, 8, 0);
putText(dst, format("num:%d", i), Point(x, y), FONT_HERSHEY_SIMPLEX, .5, Scalar(0, 0, 255), 1);
printf(" num: %d, rice area %d\n", i, area);
}
imshow("ccla-demo", dst);
imwrite("./ccla_dst.png", dst);
}
输入图像:
输出图像:
48_轮廓寻找
void cv::findContours(
cv::InputOutputArray image, // 输入的8位单通道“二值”图像
cv::OutputArrayOfArrays contours, // 包含points的vectors的vector
cv::OutputArray hierarchy, // (可选) 拓扑信息
int mode, // 轮廓检索模式
int method, // 近似方法
cv::Point offset = cv::Point() // (可选) 所有点的偏移
);
void cv::findContours(
cv::InputOutputArray image, // 输入的8位单通道“二值”图像
cv::OutputArrayOfArrays contours, // 包含points的vectors的vector
int mode, // 轮廓检索模式
int method, // 近似方法
cv::Point offset = cv::Point() // (可选) 所有点的偏移
);
cv::drawContours()用于绘制cv::findContours()找到的轮廓。使用方法其实和OpenCV3中
常用的绘图函数类似。
void cv::drawContours(
cv::InputOutputArray image, // 用于绘制的输入图像
cv::InputArrayOfArrays contours, // 点的vectors的vector
int contourIdx, // 需要绘制的轮廓的指数 (-1 表示 "all")
const cv::Scalar& color, // 轮廓的颜色
int thickness = 1, // 轮廓线的宽度
int lineType = 8, // 轮廓线的邻域模式('4'邻域 或 '8'邻域)
cv::InputArray hierarchy = noArray(), // 可选 (从 findContours得到)
int maxLevel = INT_MAX, // 轮廓中的最大下降
cv::Point offset = cv::Point() // (可选) 所有点的偏移
)
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, const char* argv[])
{
Mat src = imread("test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
Mat dst, gray, binary;
GaussianBlur(src, dst, Size(3, 3), 0, 0);
cvtColor(dst, gray, COLOR_BGR2GRAY);
threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
imshow("binary", binary);
imwrite("./binary.png", binary);
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(binary, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());
for (size_t t = 0; t < contours.size(); t++) {
drawContours(src, contours, t, Scalar(0, 0, 255), 2, 8);
}
imshow("contours", src);
waitKey(0);
return 0;
}
输入图像:
输出图像1:
输出图像2:
49_轮廓外接矩形
getStructuringElement()函数可用于构造一个特定大小和形状的结构元素,用于图像形态学处理。
cv::getStructuringElement (int shape,Size ksize,Point anchor=Point(-1,-1) )
param1:结构元素
矩形(包括线形)MORPH_RECT、椭圆(包括圆形)MORPH_ELLIPSE及十字形MORPH_CROSS。
param2:结构元素大小
param3:锚点,默认值Point(-1,-1)表示锚点位于结构元素中心
cv::Rect boundingRect( InputArray array );
输入:InputArray类型的array,输入灰度图像或二维点集。
输出:Rect类型的矩形信息,包括矩形尺寸和位置。
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, const char *argv[])
{
Mat src = imread("./test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
Mat dst, gray, binary;
Canny(src, binary, 80, 160, 3, false);
imshow("binary", binary);
imwrite("./binary.png", binary);
Mat k = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
dilate(binary, binary, k);
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(binary, contours, hi`rarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point());
for (size_t t = 0; t < contours.size(); t++) {
Rect rect = boundingRect(contours[t]);
rectangle(src, rect, Scalar(0, 0, 255), 1, 8, 0);
RotatedRect rrt = minAreaRect(contours[t]);
Point2f pts[4];
rrt.points(pts);
for (int i = 0; i < 4; i++) {
line(src, pts[i % 4], pts[(i + 1) % 4], Scalar(0, 255, 0), 2, 8, 0);
}
Point2f cpt = rrt.center;
circle(src, cpt, 2, Scalar(255, 0, 0), 2, 8, 0);
}
imshow("contours", src);
waitKey(0);
return 0;
}
50_矩形面积与周长
double contourArea( InputArray contour, bool oriented = false );
参数说明
InputArray类型的contour,输入的向量,二维点(轮廓顶点),可以为std::vector或Mat类型。
bool类型的oriented,面向区域标识符。若其为true,会返回一个带符号的面积值,正负取决于轮廓的方向。
double arcLength( InputArray curve, bool closed );
InputArray类型的curve,输入的向量,二维点(轮廓顶点),可以为std::vector或Mat类型。
bool类型的closed,用于指示曲线是否封闭的标识符,一般设置为true。
最小包围旋转矩形边框
cv::RotatedRect minAreaRect( InputArray points );
输入:InputArray类型的points,输入灰度图像或二维点集。
输出:RotatedRect类型的旋转矩形信息,即矩形四角点位置。
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, const char *argv[])
{
Mat src = imread("./test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
Mat dst, gray, binary;
Canny(src, binary, 80, 160, 3, false);
imshow("binary", binary);
imwrite("./binary.png", binary);
Mat k = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
dilate(binary, binary, k);
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(binary, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point());
for (size_t t = 0; t < contours.size(); t++) {
Rect rect = boundingRect(contours[t]);
// rectangle(src, rect, Scalar(0, 0, 255), 1, 8, 0);
double area = contourArea(contours[t]);
double curvelen = arcLength(contours[t], true);
if (area < 100 || curvelen < 100) {
continue;
}
RotatedRect rrt = minAreaRect(contours[t]);
Point2f pts[4];
rrt.points(pts);
for (int i = 0; i < 4; i++) {
line(src, pts[i % 4], pts[(i + 1) % 4], Scalar(0, 255, 0), 2, 8, 0);
}
Point2f cpt = rrt.center;
circle(src, cpt, 2, Scalar(255, 0, 0), 2, 8, 0);
}
imshow("contours", src);
waitKey(0);
return 0;
}
51_使用轮廓逼近
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
RNG rng(50000);
int main(int argc, const char *argv[])
{
Mat src = imread("./test.png");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
Mat dst, gray, binary;
cvtColor(src, gray, COLOR_BGR2GRAY);
threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
imshow("binary", binary);
imwrite("./binary.png", binary);
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(binary, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point());
Scalar color = Scalar(255, 0, 0);
for (size_t t = 0; t < contours.size(); t++) {
RotatedRect rrt = minAreaRect(contours[t]);
Point2f cpt = rrt.center;
circle(src, cpt, 2, Scalar(0, 255, 0), 2, 8, 0);
Mat result;
approxPolyDP(contours[t], result, 4, true);
printf("corners : %d\n", result.rows);
if (result.rows == 6) {
putText(src, "poly", cpt, FONT_HERSHEY_SIMPLEX, .7, color, 1, 8);
}
if (result.rows == 3) {
putText(src, "triangle", cpt, FONT_HERSHEY_SIMPLEX, .7, color, 1, 8);
}
if (result.rows == 4) {
putText(src, "rectangle", cpt, FONT_HERSHEY_SIMPLEX, .7, color, 1, 8);
}
if(result.rows > 10) {
putText(src, "circle", cpt, FONT_HERSHEY_SIMPLEX, .7, Scalar(0, 255, 0), 1, 8);
}
}
imshow("contours", src);
waitKey(0);
return 0;
}