[笔记]OpenCV+FFmpeg+Qt实现视频编辑器之OpenCV图像处理

一、通过ROI感兴趣区域来裁剪图像

1.1 cv::Rect

示例

#include <opencv2\core.hpp>
#include <opencv2\imgcodecs.hpp>
#include <opencv2\highgui.hpp>

using namespace cv;

int main(int argc, char* argv) {
	Mat src = imread(".\\res\\1.png");

	Rect rect(0, 0, 200, 200);
	Mat roi = src(rect);


	MatSize roiSize = roi.size;
	namedWindow("src");
	namedWindow("roi", WINDOW_AUTOSIZE);
	imshow("src", src);
	imshow("roi", roi);
	waitKey(0);
	return 0;
}

二、RGB、YUV、GRAY像素格式介绍opencv像素格式转换cvtColor接口讲解

像素格式和灰度图

2.1 RGB、YUV、GRAY

RGB:红绿蓝
YUV:亮度、色度、饱和度
GRAY:0-255表示亮度,颜色没有意义时用灰度图,比如OCR

2.2 cvtColor(src,img,COLOR_BGR2GRAY)

三、手动实现转换灰度图并与opencv提供的函数做性能对比

自己动手实现

转换公式:GRay = (R30 + G59 + B*11 +50)/100

#include <opencv2\core.hpp>
#include <opencv2\imgcodecs.hpp>
#include <opencv2\highgui.hpp>
#include <opencv2\imgproc.hpp>

using namespace cv;

int PrintMs(const char *text = "")
{
	static long long last = 0;
	long long cur = getTickCount();
	if (last == 0) {
		last = cur;
	}

	long long ms = ((double)(cur - last) / getTickFrequency()) * 1000;

	if (*text != 0) {
		printf("%s = %d ms\n", text, ms);
	}

	last = getTickCount();
	return 0;
}

void RGBToGray(Mat src, Mat &des) 
{
	
	des.create(src.rows, src.cols, CV_8UC1);
	for (int r = 0; r < src.rows; r++)
	{
		for (int c = 0; c < src.cols; c++)
		{
			Vec3b &m = src.at<Vec3b>(r, c);
			// GRay = (R*30 + G*59 + B*11 +50)/100
			int gray = (m[2] * 30 + m[1] * 59 + m[0] * 11 + 50) / 100;
			des.at<uchar>(r, c) = gray;
		}
	}
}

int main(int argc, char* argv) {
	Mat src = imread(".\\res\\1.png");

	Mat gray;
	Mat mygray;
	PrintMs("");
	cvtColor(src, gray, COLOR_BGR2GRAY);

	PrintMs("gray ms");
	RGBToGray(src, mygray);
	PrintMs("mygray ms");


	namedWindow("gray");
	imshow("gray", gray);
	namedWindow("mygray");
	imshow("mygray", mygray);

	namedWindow("src");
	imshow("src", src);
	waitKey(0);
	return 0;
}

在这里插入图片描述
cvtColor 使用了多线程进行计算 会快很多。

四、通过OpenCV阈值函数threshold实现图像的二值化

opencv-阈值处理

4.1 二值化和阈(yu 4)值

4.1.1 二进制阈值化

threshold(gray, bin, 100, 255, THRESH_BINARY);

4.1.2 反二进制阈值化

threshold(gray, ibin, 100, 255, THRESH_BINARY_INV);

示例代码

int main(int argc, char* argv) {
	Mat src = imread(".\\res\\1.png");
	Mat bin;
	Mat ibin;
	Mat gray;
	cvtColor(src, gray, COLOR_BGR2GRAY);
	//二进制阈值化
	threshold(gray, bin, 100, 255, THRESH_BINARY);

	//反二进制阈值化
	threshold(gray, ibin, 100, 255, THRESH_BINARY_INV);

	namedWindow("src");
	namedWindow("bin");
	namedWindow("ibin");
	imshow("src", src);
	imshow("bin", bin);
	imshow("ibin", ibin);
	waitKey(0);
	return 0;
}

五、通过OpenCV图像亮度和对比度

5.1 对比度和亮度

saturate_cast<uchar>()

在图像处理方面,无论是加是减,乘除,都会超出一个像素灰度值的范围(0~255),saturate_cast函数的作用即是:当运算完之后,结果为负,则转为0,结果超出255,则为255。

六、通过对Mat遍历修改图像亮度和对比度与convertTo性能对比

#include <opencv2\core.hpp>
#include <opencv2\imgcodecs.hpp>
#include <opencv2\highgui.hpp>
#include <opencv2\imgproc.hpp>

using namespace cv;

int PrintMs(const char *text = "")
{
	static long long last = 0;
	long long cur = getTickCount();
	if (last == 0) {
		last = cur;
	}

	long long ms = ((double)(cur - last) / getTickFrequency()) * 1000;

	if (*text != 0) {
		printf("%s = %d ms\n", text, ms);
	}

	last = getTickCount();
	return 0;
}

//
///@para a float 对比度 1.0~3.0
///@para b int 亮度 0~100
void ChangeGain(Mat &src, Mat &des, float a, int b)
{
	//g(r,c) = a*f(r,c) + b
	des.create(src.rows, src.cols, src.type());
	for (int r = 0; r < src.rows; r++)
	{
		for (int c = 0; c < src.cols; c++)
		{
			for (int i = 0; i < 3; i++)
			{
				des.at<Vec3b>(r, c)[i] = saturate_cast<uchar>(a * src.at<Vec3b>(r, c)[i] + b);
			}
		}
	}
}
int main(int argc, char *argv[])
{
	//调整对比度和亮度
	Mat src = imread(".\\res\\1.png");
	Mat des;
	PrintMs("");
	ChangeGain(src, des, 2.0, 50);
	PrintMs("ChangeGain");
	Mat des2;
	src.convertTo(des2, -1, 2.0, 50);
	PrintMs("convertTo");

	namedWindow("src");
	namedWindow("des");
	namedWindow("des2");
	imshow("src", src);
	imshow("des", des);
	imshow("des2", des2);
	waitKey(0);
	return 0;
}

在这里插入图片描述

七、图像尺寸调整算法介绍并手动实现近邻算法

是对图像进行缩放的一种方式

7.1 图像尺寸调整

INTER_NEAREST 近邻算法

性能好 效果差

CV_INTER_LINEAR 双线性内插算法(缺省使用)

性能稍差,但效果好

void xresize(Mat &src, Mat &des, Size size)
{
	des.create(size, src.type());
	//映射的原图坐标
	int sx, sy = 0;
	float fx = (float)src.cols / des.cols;
	float fy = (float)src.rows / des.rows; 
	for (int x = 0; x < des.cols; x++)
	{
		sx = fx * x + 0.5;
		for (int y = 0; y <des.rows; y++)
		{
			sy = fy * y + 0.5;
			des.at<Vec3b>(y, x) = src.at<Vec3b>(sy, sx);
		}
	}

}
int main(int argc, char *argv[])
{
	Mat src = imread("1.png"); //512*512 256 1024
	Mat img256,img1024,des256,des1024;
	resize(src, des256, Size(256, 256), 0, 0, INTER_NEAREST);

	PrintMs();
	//xresize(src, img256, Size(256, 256));
	//PrintMs("img256");
	xresize(src, img1024, Size(1024, 1024));
	//resize(src, img1024, Size(4024, 4024), 0, 0, INTER_NEAREST);
	PrintMs("img1024");
	//resize(src, des256, Size(1024, 1024), 0, 0, INTER_NEAREST);
	resize(src, des1024, Size(1024, 1024), 0, 0, INTER_LINEAR);

	PrintMs("des1024");

	namedWindow("src");
	//namedWindow("img256");
	namedWindow("des1024");
	namedWindow("img1024");
	imshow("src", src);
	imshow("img1024", img1024);
	imshow("des1024", des1024);

	//imshow("img1024", img1024);
	waitKey(0);
	return 0;
}

八、调用opencv的resize使用近邻算法并与自定义算法比较

滤波

输入图像中像素的小邻域来产生输出图像的方法,在信号处理中这种方法称为滤波( filtering)。其中,最常用的是线性滤波,输出像素是输入邻域像素的加权和。

双线性内插值

三十分钟理解:线性插值,双线性插值Bilinear Interpolation算法

  • 是由源图像位置在它附近的2*2区域4个邻近象素的值通过加权平均计算得出的
  • 低通滤波性质,使高频分量受损,图像轮廓可能会有一点模糊

九、高斯金字塔和拉普拉斯金字塔调整图像尺寸详解

图像金字塔

也是对图像进行缩放的一种方式

高斯金字塔(Gaussian pyramid)

用来向下采样缩小

  • 获取G(i+1)将G(i)与高斯内核卷积
  • 将所有偶数行和列去除
高斯内核

在这里插入图片描述

拉普拉斯金字塔(Laplacian pyramid)

用来从金字塔低层图像重建上层未采样图像 放大

  • 用来从金字塔低层图像重建上层未采样图像
  • 首先,将图像扩大两倍,新增以0填充

示例

int main(int argc, char *argv[])
{
	Mat src = imread(".\\res\\1.png"); //512*512 256 1024
	Mat gsrc;
	Mat lsrc;
	pyrDown(src, gsrc);
	pyrUp(src, lsrc);
	namedWindow("src");
	moveWindow("src", 0, 0);
	namedWindow("gsrc");
	moveWindow("gsrc", 512, 0);
	namedWindow("lsrc");
	moveWindow("lsrc", 0, 512);

	imshow("src", src);
	imshow("gsrc", gsrc);
	imshow("lsrc", lsrc);
	cvWaitKey(0);

	return 0;
}

在这里插入图片描述

十、实现两幅图像混合blending

实现两幅图像混合

  • dst = src1a+ src2(1-a)+ gammaa=[0~1]
  • 画面叠化( cross-dissolve )效果
  • addWeighted( src1, a, src2,1-a, 0.0, dst);

十一、图像旋转和镜像

图像的旋转

cv:: rotate(src, dst, type);
-ROTATE_180
-ROTATE_90_CLOCKWISE
-ROTATE 90 COUNTERCLOCKWISE

图像的镜像

cv:flip(src, dst, type); //type 0(x),1(y),-1

示例

int main(int argc, char *argv[])
{
	Mat img = imread(".\\res\\1.png");
	Mat rot;
	Mat fl;
	cv::rotate(img, rot, ROTATE_90_CLOCKWISE);
	cv::flip(img, fl,1); //type 0(x), 1(y), -1
	namedWindow("src");
	namedWindow("rot");
	namedWindow("fl");
	imshow("src", img);
	imshow("rot", rot);
	imshow("fl", fl);
	waitKey(0);
	return 0;
}

在这里插入图片描述

十二、通过ROI实现图像并排合并

int main(int argc, char *argv[])
{
	Mat img1 = imread(".\\res\\1.png");
	Mat img2 = imread(".\\res\\2.jpg");
	int height = img1.rows;
	int width1 = img1.cols;
	int width2 = img2.cols;
	// 将高图像等比缩放与低图像高度一致
	if (img1.rows > img2.rows)
	{
		height = img2.rows;
		width1 = img1.cols * ((float)img2.rows / (float)img1.rows);
		resize(img1, img1, Size(width1, height));
	}
	else if (img1.rows < img2.rows)
	{
		width2 = img2.cols * ((float)img1.rows / (float)img2.rows);
		resize(img2, img2, Size(width2, height));
	}
	//创建目标Mat
	Mat des;
	des.create(height, width1 + width2, img1.type());
	Mat r1 = des(Rect(0, 0, width1, height));
	img1.copyTo(r1);
	Mat r2 = des(Rect(width1, 0, width2, height));
	img2.copyTo(r2);

	namedWindow("des");
	imshow("des", des);
	waitKey(0);

	return 0;
}
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二进制怪兽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值