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

简介: [笔记]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;
}


相关文章
|
12天前
|
Linux 开发工具 Android开发
FFmpeg开发笔记(六十)使用国产的ijkplayer播放器观看网络视频
ijkplayer是由Bilibili基于FFmpeg3.4研发并开源的播放器,适用于Android和iOS,支持本地视频及网络流媒体播放。本文详细介绍如何在新版Android Studio中导入并使用ijkplayer库,包括Gradle版本及配置更新、导入编译好的so文件以及添加直播链接播放代码等步骤,帮助开发者顺利进行App调试与开发。更多FFmpeg开发知识可参考《FFmpeg开发实战:从零基础到短视频上线》。
64 2
FFmpeg开发笔记(六十)使用国产的ijkplayer播放器观看网络视频
|
22天前
|
并行计算 PyTorch TensorFlow
Ubuntu安装笔记(一):安装显卡驱动、cuda/cudnn、Anaconda、Pytorch、Tensorflow、Opencv、Visdom、FFMPEG、卸载一些不必要的预装软件
这篇文章是关于如何在Ubuntu操作系统上安装显卡驱动、CUDA、CUDNN、Anaconda、PyTorch、TensorFlow、OpenCV、FFMPEG以及卸载不必要的预装软件的详细指南。
1968 3
|
19天前
|
编解码 语音技术 内存技术
FFmpeg开发笔记(五十八)把32位采样的MP3转换为16位的PCM音频
《FFmpeg开发实战:从零基础到短视频上线》一书中的“5.1.2 把音频流保存为PCM文件”章节介绍了将媒体文件中的音频流转换为原始PCM音频的方法。示例代码直接保存解码后的PCM数据,保留了原始音频的采样频率、声道数量和采样位数。但在实际应用中,有时需要特定规格的PCM音频。例如,某些语音识别引擎仅接受16位PCM数据,而标准MP3音频通常采用32位采样,因此需将32位MP3音频转换为16位PCM音频。
40 0
FFmpeg开发笔记(五十八)把32位采样的MP3转换为16位的PCM音频
|
22天前
|
计算机视觉
Opencv学习笔记(八):如何通过cv2读取视频和摄像头来进行人脸检测(jetson nano)
如何使用OpenCV库通过cv2模块读取视频和摄像头进行人脸检测,并提供了相应的代码示例。
64 1
|
21天前
|
Ubuntu 应用服务中间件 nginx
Ubuntu安装笔记(三):ffmpeg(3.2.16)源码编译opencv(3.4.0)
本文是关于Ubuntu系统中使用ffmpeg 3.2.16源码编译OpenCV 3.4.0的安装笔记,包括安装ffmpeg、编译OpenCV、卸载OpenCV以及常见报错处理。
92 2
Ubuntu安装笔记(三):ffmpeg(3.2.16)源码编译opencv(3.4.0)
|
15天前
|
Java 数据安全/隐私保护
Java ffmpeg 实现视频加文字/图片水印功能
【10月更文挑战第22天】在 Java 中使用 FFmpeg 实现视频加文字或图片水印功能,需先安装 FFmpeg 并添加依赖(如 JavaCV)。通过构建 FFmpeg 命令行参数,使用 `drawtext` 滤镜添加文字水印,或使用 `overlay` 滤镜添加图片水印。示例代码展示了如何使用 JavaCV 实现文字水印。
|
16天前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
63 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
20天前
|
计算机视觉 Python
FFMPEG学习笔记(一): 提取视频的纯音频及无声视频
本文介绍了如何使用FFmpeg工具从视频中提取纯音频和无声视频。提供了具体的命令行操作,例如使用`ffmpeg -i input.mp4 -vn -c:a libmp3lame output.mp3`来提取音频,以及`ffmpeg -i input.mp4 -c:v copy -an output.mp4`来提取无声视频。此外,还包含了一个Python脚本,用于批量处理视频文件,自动提取音频和生成无声视频。
30 1
|
21天前
|
缓存 监控 计算机视觉
视频监控笔记(三):opencv结合ffmpeg获取rtsp摄像头相关信息
本文介绍了如何使用OpenCV结合FFmpeg获取RTSP摄像头信息,包括网络架构、视频监控系统组成、以及如何读取和显示网络摄像头视频流。
36 1
|
21天前
|
编解码 关系型数据库 计算机视觉
Opencv学习笔记(十一):opencv通过mp4保存为H.264视频
本文介绍了如何在OpenCV中通过使用cisco开源的openh264库来解决不支持H.264编码的问题,并提供了完整的代码示例。
42 0
Opencv学习笔记(十一):opencv通过mp4保存为H.264视频