读取图片or读取视频
//读取图片
cv::Mat src = imread("你的图片的绝对路径");
//显示图片
cv::imshow("窗口名字",src);
//等待
cv::waitKey();//输入数字,则等待数字对应的毫秒数,不输入或输入为0则默认一直等待到按键
//读取视频
cv::Mat pic;
cv::VideoCapture capture;
capture.open("视频地址");
capture>>pic;
//这样就可以获取视频的第一帧了
int totalFrames=capture.get(cv::CAP_PROP_FRAME_COUNT);
//这个函数可以获得视频的总帧数
int currentFrames=0;
while(1){
capture>>pic;
if(currentFrames==totalFrames-1){
current.set(cv::CAP_PROP_POS_FRAMES,0);
}
cv::imshow("result",pic);
currentFrames++;
}
//以上可以一帧一帧看视频,并且可以实现视频循环播放
有关窗口
//创建新窗口
namedWindow("newWindow", 1);
//移动指定窗口到x、y位置
moveWindow("newWindow", 1000, 1000);
//改变指定窗口大小
resizeWindow("newWindow", 900, 1000);
//等待
waitKey();
//销毁指定窗口
destroyWindow("newWindow");
//销毁所有窗口
destroyAllWindows();
cvtColor
函数说明:void cv::cvtColor( InputArray src, OutputArray dst, int code, int dstCn = 0 )
输入参数:
src 输入图像:8位无符号、16位无符号(CV_16UC…)或单精度浮点。
dst 输出与src大小和深度相同的图像。
dstCn 输出图像的通道数,默认0。如果参数为0,那么通道的数量将自动从src和code中导出。
code 颜色空间转换码。总计有200种左右,只列出其中常用转换码。
cv::ColorConversionCodes {
cv::COLOR_BGR2RGB = 4,
cv::COLOR_RGB2BGR = COLOR_BGR2RGB,
cv::COLOR_BGR2GRAY = 6,
cv::COLOR_RGB2GRAY = 7,
cv::COLOR_GRAY2BGR = 8,
cv::COLOR_GRAY2RGB = COLOR_GRAY2BGR
}
备注1:若设置dst==src,即实现原图的转换。但不改变原矩阵,而是将src.data存放在编译器新建的内存地址中。
Mat src = imread("D:/系统默认/桌面/RM/sha.jpeg");
Mat dstrgb;
Mat dstgray;
cvtColor(src, dstrgb, COLOR_BGR2RGB, 0);
cvtColor(src, dstgray, COLOR_BGR2GRAY, 0);
imshow("img", src);
imshow("RGB", dstrgb);
imshow("GRAY", dstgray);
waitKey()
边缘填充
#include <opencv2/core.hpp>
函数说明:void cv::copyMakeBorder( InputArray src, OutputArray dst, int top, int bottom, int left, int right, int borderType, const Scalar &value = Scalar() );
输入参数:
src 输入图像。
dst 与src类型相同的输出图像,大小为size(src.cols+left+right, src.rows+top+bottom)。
top 顶部像素
bottom 底部像素
left 左侧像素
right 右侧像素。指定在源图像的每个方向上要外推的像素数。top=1,bottom=1,left=1,right=1意味着需要构建像素宽为1的边界。
borderType 边框类型(即边界填充方式)。其中,BORDER_TRANSPARENT不可用。
cv::BORDER_CONSTANT = 0 iiiiii|abcdefgh|iiiiiii 常量法。填充常数值
cv::BORDER_REPLICATE = 1 aaaaaa|abcdefgh|hhhhhhh 复制法。复制最边缘像素
cv::BORDER_REFLECT = 2 fedcba|abcdefgh|hgfedcb 反射法。以两边为轴
cv::BORDER_WRAP = 3 cdefgh|abcdefgh|abcdefg 外包装法。
cv::BORDER_REFLECT_101 = 4 gfedcb|abcdefgh|gfedcba 反射法。以最边缘像素为轴
cv::BORDER_TRANSPARENT = 5 uvwxyz|abcdefgh|ijklmno
cv::BORDER_REFLECT101 = 6 same as BORDER_REFLECT_101
cv::BORDER_DEFAULT = 7 same as BORDER_REFLECT_101
cv::BORDER_ISOLATED = 8 do not look outside of ROI
value = Scalar() 如果borderType==Border_CONSTANT,则为边界值。
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
//using namespace std;
//using namespace cv;
int main(int argc, char* argv[])
{
//(1)读取图像
std::string img_path = "D:/系统默认/桌面/RM/sha.jpeg";
cv::Mat src = cv::imread(img_path, 1);
//(2)判断图像是否读取成功
if (!src.data)
{
std::cout << "can't read image!" << std::endl;
return -1;
}
//(3)边缘填充
float border_width = 0.2;
int top = (int)(border_width * src.rows);
int bottom = (int)(border_width * src.rows);
int left = (int)(border_width * src.cols);
int right = (int)(border_width * src.cols);
cv::RNG rng;
cv::Mat img1, img2, img3, img4, img5, img6, img7, img8, img9;
cv::Scalar color = cv::Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
cv::copyMakeBorder(src, img1, top, bottom, left, right, cv::BORDER_CONSTANT, color);
cv::copyMakeBorder(src, img2, top, bottom, left, right, cv::BORDER_REPLICATE, color);
cv::copyMakeBorder(src, img3, top, bottom, left, right, cv::BORDER_REFLECT, color);
cv::copyMakeBorder(src, img4, top, bottom, left, right, cv::BORDER_WRAP, color);
cv::copyMakeBorder(src, img5, top, bottom, left, right, cv::BORDER_REFLECT_101, color);
//cv::copyMakeBorder(src, img6, top, bottom, left, right, cv::BORDER_TRANSPARENT, color); //不可用
cv::copyMakeBorder(src, img7, top, bottom, left, right, cv::BORDER_REFLECT101, color);
cv::copyMakeBorder(src, img8, top, bottom, left, right, cv::BORDER_DEFAULT, color);
cv::copyMakeBorder(src, img9, top, bottom, left, right, cv::BORDER_ISOLATED, color);
//(4)显示图像
cv::imshow("src", src);
cv::imshow("img1", img1);
cv::imshow("img2", img2);
cv::imshow("img3", img3);
cv::imshow("img4", img4);
cv::imshow("img5", img5);
//cv::imshow("img6", img6); //不可用
cv::imshow("img7", img7);
cv::imshow("img8", img8);
cv::imshow("img9", img9);
cv::waitKey(0);
return 0;
}
图像变换
图像缩放
- 若调整src与dst对齐:
resize(src, dst, dst.size(), 0, 0, interpolation);
- 若在输入图像的基础上进行等比例缩放:
resize(src, dst, Size(), 0.5, 0.5, interpolation);
#include <opencv2/imgproc.hpp>
函数说明:void cv::resize( InputArray src, OutputArray dst, Size dsize, double fx = 0, double fy = 0, int interpolation = INTER_LINEAR )
输入参数:
src 输入图像:8位无符号、16位无符号(CV_16UC…)或单精度浮点。
dst 输出图像;大小为dsize(当它为非零时)或根据src.size()、fx和fy计算的大小;dst的类型与src的类型相同。
dsize 输出图像大小;dsize=None,则计算为:dsize = Size(round(fx*src.cols), round(fy*src.rows)),dsize或fx和fy都必须为非零。
fx = 0 沿水平轴的缩放比例;当它等于0时,它被计算为:(double)dsize.width/src.cols
fy = 0 沿垂直轴的缩放比例;当它等于0时,它被计算为:(double)dsize.height/src.rows
interpolation = INTER_LINEAR 插值方法。
cv::InterpolationFlags{
cv::INTER_NEAREST 最近邻插值
cv::INTER_LINEAR 双线性插值(默认)
cv::INTER_CUBIC 双三次插值
cv::INTER_AREA 使用像素面积关系进行重新采样。
cv::INTER_LANCZOS4 8x8邻域上的Lanczos插值
cv::INTER_LINEAR_EXACT 位精确双线性插值
cv::INTER_NEAREST_EXACT 位精确最近邻插值。这将产生与PIL、scikit图像或Matlab中的最近邻方法相同的结果。
cv::INTER_MAX 插值代码掩码
cv::WARP_FILL_OUTLIERS 标志,填充所有目的地图像像素。如果其中一些对应于源图像中的异常值,则将其设置为零。
cv::WARP_INVERSE_MAP 标志,逆变换
}
图像翻转
#include <opencv2/core.hpp>
函数说明:void cv::flip( InputArray src, OutputArray dst, int flipCode );
输入参数:
src 输入数组。
dst 输出数组。与src相同大小和类型。
flipCode 翻转标志。
11、0表示绕x轴翻转。
22、正值(例如1)表示绕y轴翻转。
33、负值(例如-1)意味着在两个轴上翻转。
图像旋转
#include <opencv2/imgproc.hpp>
函数说明:Mat cv::getRotationMatrix2D( Point2f center, double angle, double scale );
输入参数:
center 输入图像的旋转中心坐标。一般取图像的中心点,可自定义。
angle 旋转角度(以度为单位)。正值表示逆时针旋转(坐标原点假定为左上角)。
scale 各向比例尺度因子。
计算仿射变换的2×3矩阵:
#include <opencv2/imgproc.hpp>
函数说明:Mat cv::getAffineTransform( const Point2f src[], const Point2f dst[] );
输入参数:
src 输入图像中三角形的顶点坐标。
dst 输出图像中对应三角形的顶点坐标。
计算透视变换的3×3矩阵
#include <opencv2/imgproc.hpp>
函数说明:Mat cv::getPerspectiveTransform( InputArray src, InputArray dst, int solveMethod = DECOMP_LU );
输入参数:
src 输入图像中四边形的顶点坐标。
dst 输入图像中对应四边形的顶点坐标。
solveMethod = DECOMP_LU 解决方法。
cv::DECOMP_LU 选择最优的元素进行高斯消除。
DECOMP_SVD 奇异值分解法。系统可以是过定义的,并且/或者矩阵src1可以是奇异的
DECOMP_EIG 特征值分解。矩阵src1必须是对称的
DECOMP_CHOLESKY Cholesky LLT分解。矩阵src1必须是对称的并且是正定义的
DECOMP_QR QR分解。系统可以是过定义的,并且/或者矩阵src1可以是奇异的
DECOMP_NORMAL 虽然前面的所有标志都是互斥的,但这个标志可以与前面的任何标志一起使用;这意味着使用通用公式(src1转置*src1*dst=src1转置*src2),而不是原系统(src1⋅dst=src2)
仿射变换:cv::warpAffine()
仿射变换(Affine Transformation):二维坐标到二维坐标的变换,其本质上就是多种变换的叠加。包括:缩放、平移、旋转、反射。 仿射变换(Affine Transformation)原理及应用
仿射的含义:
(1)共线性:若几个点在一条线上(变换前),则变换后仍然在一条线上。
(2)平行性:若两条线平行(变换前),则(变换后)仍然平行。
(3)共线比例不变性:若两条线段成比例(变换前),则(变换后)比例不变。
由于仿射特性,变换后仍是平行四边形,故只需要非共线的三个点就能确定。三个坐标点没有固定顺序,但变换前后的矩阵必须是对应的。
#include <opencv2/imgproc.hpp>
函数说明:void cv::warpAffine( InputArray src, OutputArray dst, InputArray M, Size dsize, int flags = INTER_LINEAR, int borderMode = BORDER_CONSTANT, const Scalar &borderValue = Scalar() );
输入参数:
(1)src 输入图像。
(2)dst 输出图像。输出大小为dsize且类型与src相同的图像。
(3)M 2×3变换矩阵。2x3是三角形的三个顶点[x, y]。仿射变换只需要三个点,三点即可确定一个平行四边形。
(4)dsize 输出图像的大小。
(5)flags = INTER_LINEAR 插值方法。
cv::INTER_NEAREST 最近邻插值
cv::INTER_LINEAR 双线性插值(默认)
cv::INTER_CUBIC 双三次插值
cv::INTER_AREA 使用像素面积关系进行重新采样。
cv::INTER_LANCZOS4 8x8邻域上的Lanczos插值
cv::INTER_LINEAR_EXACT 位精确双线性插值
cv::INTER_NEAREST_EXACT 位精确最近邻插值。这将产生与PIL、scikit图像或Matlab中的最近邻方法相同的结果。
cv::INTER_MAX 插值代码掩码
cv::WARP_FILL_OUTLIERS 标志,填充所有目的地图像像素。如果其中一些对应于源图像中的异常值,则将其设置为零。
cv::WARP_INVERSE_MAP 标志,逆变换
(6)borderMode = BORDER_CONSTANT 边界类型(即边界填充方式)。
cv::BORDER_CONSTANT = 0 iiiiii|abcdefgh|iiiiiii 常量法。填充常数值
cv::BORDER_REPLICATE = 1 aaaaaa|abcdefgh|hhhhhhh 复制法。复制最边缘像素
cv::BORDER_REFLECT = 2 fedcba|abcdefgh|hgfedcb 反射法。以两边为轴
cv::BORDER_WRAP = 3 cdefgh|abcdefgh|abcdefg 外包装法。
cv::BORDER_REFLECT_101 = 4 gfedcb|abcdefgh|gfedcba 反射法。以最边缘像素为轴
cv::BORDER_TRANSPARENT = 5 uvwxyz|abcdefgh|ijklmno
cv::BORDER_REFLECT101 = 6 same as BORDER_REFLECT_101
cv::BORDER_DEFAULT = 7 same as BORDER_REFLECT_101
cv::BORDER_ISOLATED = 8 do not look outside of ROI
(7)borderValue = Scalar() 边界值(在边界不变的情况下)。缺省值是0。
透视变换
透视变换(Perspective Transformation):将二维图片投影到三维平面上,然后再转换到二维坐标下,所以也称为投影映射(Projective Mapping)。透视变换包括了所有的仿射变换。
透视变换相比仿射变换更加灵活,变换后会产生一个新的四边形,但不一定是平行四边形,所以需要非共线的四个点才能确定。四个坐标点没有固定顺序,但变换前后的矩阵必须是对应的。OpenCV4 详解仿射变换和透视变换和C++实现
#include <opencv2/imgproc.hpp>
函数说明:
void cv::warpPerspective( InputArray src, OutputArray dst, InputArray M, Size dsize, int flags = INTER_LINEAR, int borderMode = BORDER_CONSTANT, const Scalar &borderValue = Scalar() );
输入参数:
(1)src 输入图像。
(2)dst 输出图像。输出大小为dsize且类型与src相同的图像。
(3)M 3×3变换矩阵。
(4)dsize 输出图像的大小。
(5)flags = INTER_LINEAR 插值方法。
cv::INTER_NEAREST 最近邻插值
cv::INTER_LINEAR 双线性插值(默认)
cv::INTER_CUBIC 双三次插值
cv::INTER_AREA 使用像素面积关系进行重新采样。
cv::INTER_LANCZOS4 8x8邻域上的Lanczos插值
cv::INTER_LINEAR_EXACT 位精确双线性插值
cv::INTER_NEAREST_EXACT 位精确最近邻插值。这将产生与PIL、scikit图像或Matlab中的最近邻方法相同的结果。
cv::INTER_MAX 插值代码掩码
cv::WARP_FILL_OUTLIERS 标志,填充所有目的地图像像素。如果其中一些对应于源图像中的异常值,则将其设置为零。
cv::WARP_INVERSE_MAP 标志,逆变换
(6)borderMode = BORDER_CONSTANT 边界类型(即边界填充方式)。
cv::BORDER_CONSTANT = 0 iiiiii|abcdefgh|iiiiiii 常量法。填充常数值
cv::BORDER_REPLICATE = 1 aaaaaa|abcdefgh|hhhhhhh 复制法。复制最边缘像素
cv::BORDER_REFLECT = 2 fedcba|abcdefgh|hgfedcb 反射法。以两边为轴
cv::BORDER_WRAP = 3 cdefgh|abcdefgh|abcdefg 外包装法。
cv::BORDER_REFLECT_101 = 4 gfedcb|abcdefgh|gfedcba 反射法。以最边缘像素为轴
cv::BORDER_TRANSPARENT = 5 uvwxyz|abcdefgh|ijklmno
cv::BORDER_REFLECT101 = 6 same as BORDER_REFLECT_101
cv::BORDER_DEFAULT = 7 same as BORDER_REFLECT_101
cv::BORDER_ISOLATED = 8 do not look outside of ROI
(7)borderValue = Scalar() 边界值(在边界不变的情况下)。缺省值是0。
实例
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{
//(1)读取图像
string img_path1 = "D:/系统默认/桌面/RM/sha.jpeg";
string img_path2 = "D:/系统默认/桌面/RM/tou.jpeg";
Mat src1 = imread(img_path1, 1);
Mat src2 = imread(img_path2, 1);
if (src1.empty() || src2.empty()) {
cout << "can't read image!!" << endl;
return -1;
}
if (src1.rows != src2.rows || src1.cols != src2.cols) {
cout << "src1=" << src1.rows << ":" << src1.cols << endl;
cout << "src2=" << src2.rows << ":" << src2.cols << endl;
//把2的尺寸改成和1一样大小
resize(src2, src2, src1.size(), 0, 0, INTER_LINEAR);
//这个时候再来看尺寸
cout << "src1=" << src1.rows << ":" << src1.cols << endl;
cout << "src2=" << src2.rows << ":" << src2.cols << endl;
}
Mat resize_B, resize_S;
resize(src1, resize_B, Size(0, 0), 1, 2, INTER_LINEAR);
resize(src1, resize_S, Size(0, 0), 0.8,0.8, INTER_LINEAR);
cout << "resize_B=" << resize_B.rows << ":" << resize_B.cols << endl;
cout << "resize_S=" << resize_S.rows << ":" << resize_S.cols << endl;
imshow("src1", src1);
imshow("src2", src2);
imshow("resize_B", resize_B);
imshow("resize_S", resize_S);
//图像翻转
Mat src_flip;
flip(src1, src_flip, 0);
imshow("flip", src_flip);
//(6)图像旋转(封装函数)
//Mat src_rotate;
Mat rotatedst;
int angle = 45;
int width = src1.rows;
int height = src1.cols;
Mat Matrix = getRotationMatrix2D(Point2f(width / 2, height / 2), angle, 1.0);
double cos = abs(Matrix.at<double>(0, 0));
double sin = abs(Matrix.at<double>(0, 1));
int nw = cos * width + sin * height;
int nh = sin * width + cos * height;
Matrix.at<double>(0, 2) += (nw / 2 - width/2);
Matrix.at<double>(1, 2) += (nh / 2 - height / 2);
warpAffine(src1, rotatedst, Matrix, Size(nh, nw));
imshow("rotatedst", rotatedst);
/*//图像平移
Mat transdst;
int height = src1.cols;
int wight = src1.rows;
int tx = 20;
int ty = 50;
float warp_values[] = { 1.0,0.0,tx,0.0,1.0,ty };
Mat translation_matrix = Mat(2, 3, CV_32F, warp_values);
warpAffine(src1, transdst, translation_matrix, src1.size());
imshow("transdst", transdst);*/
//仿射变换
Mat src_wrap;
Point2f src_xy[3];
Point2f dst_xy[3];
src_xy[0] = cv::Point2f(0, 0); //计算输入图像的三点坐标
src_xy[1] = cv::Point2f(src1.cols - 1, 0);
src_xy[2] = cv::Point2f(0, src1.rows - 1);
dst_xy[0] = cv::Point2f(src1.cols * 0.0, src1.rows * 0.33); //计算输入图像变换后对应的三点坐标
dst_xy[1] = cv::Point2f(src1.cols * 0.85, src1.rows * 0.25);
dst_xy[2] = cv::Point2f(src1.cols * 0.15, src1.rows * 0.7);
Mat warp_mat = getAffineTransform(src_xy, dst_xy);
warpAffine(src1, src_wrap, warp_mat, src1.size());
//标记坐标点
Mat src_WW(src1);
for (int i = 0; i < 4; i++) {
circle(src_WW, src_xy[i], 2, Scalar(0, 0, 255), 2);
circle(src_wrap, dst_xy[i], 2, Scalar(0, 0, 255), 2);
}
imshow("src_WW", src_WW);
//透视变换
Mat src_Pers;
Point2f srcPoints[4] = { Point2f(0,0),Point2f(src1.cols - 1,0),Point2f(0,src1.rows - 1),Point2f(src1.cols - 1,src1.cols - 1) };
Point2f dstPoints[4] = { Point2f(0,0),Point2f(100,0),Point2f(0,100),Point(150,100) };
Mat Trans = getPerspectiveTransform(srcPoints, dstPoints);
warpPerspective(src1, src_Pers, Trans, Size(src1.cols, src1.rows));
Mat src1_PP(src1);
for (int i = 0; i < 4; i++) {
circle(src1_PP, srcPoints[i],2, Scalar(0, 0, 255), 2);
circle(src_Pers, dstPoints[i], 2, Scalar(0, 0, 255), 2);
}
imshow("src1_PP", src1_PP);
imshow("src_wrap", src_wrap);
imshow("src_Pers", src_Pers);
waitKey();
return 0;
}
图像滤波
Mat src = imread("D:/系统默认/桌面/RM/dirtyRabbit.jpg", IMREAD_UNCHANGED);
Mat dst1, dst2, dst3, dst4, dst5;
blur(src, dst1, Size(3, 3));
GaussianBlur(src, dst2, Size(3, 3), 3.0);
medianBlur(src, dst3, 3);
bilateralFilter(src, dst4, 20, 200, 10);
Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
filter2D(src, dst5, src.depth(),kernel);
imshow("均值滤波", dst1);
imshow("高斯滤波", dst2);
imshow("中值滤波", dst3);
imshow("双边滤波", dst4);
imshow("不知道", dst5);
waitKey();
return 0;;
参考文章链接:Opencv C++图像处理(全)_c++ opencv 图像处理-优快云博客
旋转平移还不会的话请看:Opencv 基础(四):使用OpenCV进行图像旋转和平移_opencv图像旋转-优快云博客