opencv图片处理

news2024/11/28 16:52:02

目录

  • 1 图片处理
    • 1.1 显示图片
    • 1.2 旋转图片
    • 1.3 合并图片
    • 1.4、Mat类
      • 1.4.1、像素的储存结构
      • 1.4.2、访问像素数据
    • 1.6、rgb转灰度图
    • 1.7、二值化
    • 1.8、对比度和亮度
    • 1.9、图片缩放
      • 1.9.1、resize
        • 临近点算法
        • 双线性内插值
      • 1.9.2、金字塔缩放
    • 1.10、图片叠加


1 图片处理

1.1 显示图片

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

using namespace cv;

int main(int argc, char *argv[])
{
    Mat image = imread("test.jpeg");
    namedWindow("img");
    imshow("img", image);
    waitKey(0);
}

1.2 旋转图片

旋转图片用的是rotate(InputArray src, OutputArray dst, int rotateCode)方法,opencv提供了以下3种旋转方式。

enum RotateFlags {
    ROTATE_90_CLOCKWISE = 0, //顺时针旋转90度
    ROTATE_180 = 1, //旋转180度
    ROTATE_90_COUNTERCLOCKWISE = 2 //逆时针旋转90度
};
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>

using namespace cv;

int main(int argc, char *argv[])
{
    Mat src= imread("test.jpeg");
    Mat dst;
    rotate(src, dst, ROTATE_90_CLOCKWISE); //顺时针旋转90度
    namedWindow("img");
    imshow("img", dst);
    waitKey(0);
}

在这里插入图片描述

1.3 合并图片

把两张图片合并到一张。
思路:创建一个能容纳两张图片的Mat,然后对左右两个区域分别填充像素。

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

using namespace cv;

int main(int argc, char *argv[])
{
    Mat img1 = imread("test1.jpeg");
    Mat img2 = imread("test.jpeg");

    Mat dst;
    dst.create(img1.rows > img2.rows ? img1.rows : img2.rows,
               img1.cols + img2.cols, 
               img1.type());
    Mat r1 = dst(Rect(0, 0, img1.cols, img1.rows));
    img1.copyTo(r1);
    Mat r2 = dst(Rect(img1.cols, 0, img2.cols, img2.rows));
    img2.copyTo(r2);

    namedWindow("img");
    imshow("img", dst);
    waitKey(0);
}

在这里插入图片描述

1.4、Mat类

opencv的Mat类对象可以用来存放图像的像素数据,它有多种储存模式,比较常用的有以下四种。

#define CV_8UC1 CV_MAKETYPE(CV_8U,1)
#define CV_8UC2 CV_MAKETYPE(CV_8U,2)
#define CV_8UC3 CV_MAKETYPE(CV_8U,3)
#define CV_8UC4 CV_MAKETYPE(CV_8U,4)

它们的含义可以根据名字来判别,比如CV_8UC3,代表一个像素由3个8位的uchar储存,我们平时看到的rgb三色图就可以用这种类型来储存。

1.4.1、像素的储存结构

Mat对象的像素数据存放在一个char类型数据上,成员名叫data。
以一张CV_8UC3类型、大小为2 * 2的图像为例,它对应的储存结构可以以下图表示。
在这里插入图片描述
在显示图像时,映射成下图所示。
在这里插入图片描述

1.4.2、访问像素数据

从上一节我们可以看到,像素数据里的红蓝绿数据是以蓝(0),绿(1),红(2)的顺序来排列的。比如我们要访问第一行第一列的绿色数据,可以用mat.data[1]来访问,访问第二行第一列的红色数据,可以用mat.data[8]。

下面举例说明opencv修改像素数据的方式。
比如我们要用opencv来画一幅红蓝间条的图片,可以用以下程序来实现。

#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>

using namespace cv;

int main(int argc, char *argv[])
{
    Mat mat(400, 300, CV_8UC3); 			//创建一张400 * 300的图片
    int pixelSize = mat.elemSize();			//单个像素的大小,本例中大小为3
    int size = mat.rows * mat.cols * pixelSize;	//行*列*像素大小 = 缓存区大小
    for (int i = 0; i < size; i += pixelSize) {
    	/* 每隔十行切换一次颜色 */
        int row = i / (mat.cols * pixelSize);	
        if (row % 20 < 10) {
            /* 画蓝色像素点 */
            mat.data[i] = 255;
            mat.data[i + 1] = 0;
            mat.data[i + 2] = 0;
        } else {
            /* 画红色像素点 */
            mat.data[i] = 0;
            mat.data[i + 1] = 0;
            mat.data[i + 2] = 255;
        }
    }
    namedWindow("mat");
    imshow("mat", mat);
    waitKey(0);
}

opencv中除了用mat.data可以访问像素数据外,还提供了几种访问方式,如下表所示。
mat.step代表一行的大小,即colSum * ps。

编号访问方式特点例子(访问第r行第c列的蓝色)
1mat.data[index]遍历速度和访问速度都是最快的,但使用不便。data[r * mat.step + c + 0]
2mat.ptr(row, col)速度比第一种稍慢,可以通过行号和列号来直接访问。mat.ptr(row, col)[0]
3mat.at(row, col)速度最慢,可以通过行号和列号来直接访问。mat.at(row, col)[0]

以上效率是用opencv3.4测得的,不同版本的效率可能不一样。
测试例程:

#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <QDebug>
#include <QElapsedTimer>

using namespace cv;

int main(int argc, char *argv[])
{
//    printMs();
    Mat mat(3000, 4000, CV_8UC3);
    int pixelSize = mat.elemSize();
    QElapsedTimer timer;

    timer.start();
    for (int r = 0; r < mat.rows; ++r) {
        for (int c = 0; c < mat.cols; ++c) {
            int rowStep = r * mat.step;
            int colIndex = c * pixelSize ;
            mat.data[rowStep + colIndex ] = 0;//B
            mat.data[rowStep + colIndex + 1] = 255;//G
            mat.data[rowStep + colIndex + 2] = 0;//R
        }
    }
    qDebug() << QString("%1: %2ms").arg("step").arg(timer.elapsed());

    timer.start();
    for (int r = 0; r < mat.rows; ++r) {
        for (int c = 0; c < mat.cols; ++c) {
            Vec3b *pixel = mat.ptr<Vec3b>(r, c);
            pixel->val[0] = 0;//B
            pixel->val[1] = 255;//G
            pixel->val[2] = 0;//R
        }
    }
    qDebug() << QString("%1: %2ms").arg("ptr").arg(timer.elapsed());

    timer.start();
    for (int r = 0; r < mat.rows; ++r) {
        for (int c = 0; c < mat.cols; ++c) {
            Vec3b &pixel = mat.at<Vec3b>(r, c);
            pixel.val[0] = 0;//B
            pixel.val[1] = 255;//G
            pixel.val[2] = 0;//R
        }
    }
    qDebug() << QString("%1: %2ms").arg("at").arg(timer.elapsed());

    timer.start();
    auto it = mat.begin<Vec3b>(), end = mat.end<Vec3b>();
    for (; it != end; ++it) {
        (*it).val[0] = 0;//B
        (*it).val[1] = 255;//G
        (*it).val[2] = 255;//R
    }
    qDebug() << QString("%1: %2ms").arg("it").arg(timer.elapsed());

    namedWindow("mat");
    imshow("mat", mat);
    waitKey(0);
}
"step: 45ms"
"ptr: 54ms"
"at: 96ms"
"it: 102ms"

1.6、rgb转灰度图

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

using namespace cv;

int main(int argc, char *argv[])
{
    Mat img = imread("test.jpeg");
    Mat gray;
    cvtColor(img , gray, COLOR_BGR2GRAY);
    namedWindow("gray");
    imshow("gray", gray);
    waitKey(0);
}

在这里插入图片描述

1.7、二值化

二值化含义:把灰度大于阀值的用白色显示,小于阀值的像素用黑色显示。
opencv函数threshold(src, dst, thresh, maxval, type);

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

using namespace cv;

int main(int argc, char *argv[])
{
    Mat src = imread("test.jpeg");
    Mat gray;
    Mat bin;
    cvtColor(src, gray, COLOR_BGR2GRAY);
    threshold(gray, bin, 100, 255, THRESH_BINARY);
//    threshold(gray, bin, 100, 255, THRESH_BINARY_INV);

    namedWindow("img");
 	imshow("img", bin);
    waitKey(0);

}

在这里插入图片描述

1.8、对比度和亮度

对比度和亮度利用公式来计算:g(i, j) = a * f(i, j) + b
a代表对比度(1.0 ~ 3.0),b代表亮度(0 ~ 100)。

void myConvert(Mat &src, Mat &dst, float a, float b) 
{
	dst.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) {
		    	/* saturate_cast<uchar>限制表达式的结果最大为uchar的大小,也就是255 */
				dst.at<Vec3b>(r,, c)[i]  = saturate_cast<uchar>(a * src.at<Vec3b>(r, c)[i] + b);
			}
 		}
	}
}

opencv提供的接口是convertTo。

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

using namespace cv;

int main(int argc, char *argv[])
{
    Mat src = imread("test.jpeg");
    Mat dst;

    src.convertTo(dst, -1, 2.0, 50);    //类型填负数代表与src一致

    namedWindow("img");
    imshow("img", dst);

    waitKey(0);
}

在这里插入图片描述

1.9、图片缩放

1.9.1、resize

opencv为图片缩放提供了resize(src, dst, dsize, fx = 0, fy = 0, interpolation = INTER_LINEAR)函数。

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

using namespace cv;

int main(int argc, char *argv[])
{
    Mat src = imread("test.jpeg");
    Mat dst;

    resize(src, dst, Size(300, 300), 0, 0, INTER_NEAREST);

    namedWindow("src");
    imshow("src", src);

    namedWindow("dst");
    imshow("dst", dst);

    waitKey(0);
}

在这里插入图片描述
resize的最后一个参数interpolation是缩放使用的算法类型,opencv提供了以下几种算法。

enum InterpolationFlags{
    /** nearest neighbor interpolation */
    INTER_NEAREST        = 0,
    /** bilinear interpolation */
    INTER_LINEAR         = 1,
    /** bicubic interpolation */
    INTER_CUBIC          = 2,
    /** resampling using pixel area relation. It may be a preferred method for image decimation, as
    it gives moire'-free results. But when the image is zoomed, it is similar to the INTER_NEAREST
    method. */
    INTER_AREA           = 3,
    /** Lanczos interpolation over 8x8 neighborhood */
    INTER_LANCZOS4       = 4,
    /** Bit exact bilinear interpolation */
    INTER_LINEAR_EXACT = 5,
    /** mask for interpolation codes */
    INTER_MAX            = 7,
    /** flag, fills all of the destination image pixels. If some of them correspond to outliers in the
    source image, they are set to zero */
    WARP_FILL_OUTLIERS   = 8,
    /** flag, inverse transformation

    For example, #linearPolar or #logPolar transforms:
    - flag is __not__ set: \f$dst( \rho , \phi ) = src(x,y)\f$
    - flag is set: \f$dst(x,y) = src( \rho , \phi )\f$
    */
    WARP_INVERSE_MAP     = 16
};

下面对INTER_NEAREST(临近点算法)和INTER_LINEAR(双线性内插值)做介绍。

临近点算法

原理:
在这里插入图片描述

特点:速度最快,会失真,不够平滑。

双线性内插值

原理:用像素点的临近四个点做平均计算。
在这里插入图片描述

特点:速度稍慢一点,平滑效果比临近点算法好,但图像的边界的棱角会被平均而模糊掉。

1.9.2、金字塔缩放

opencv提供了向上重建(拉普拉斯金字塔,放大)的pyrUp()和向下采样(高斯金字塔,缩小)的pyrDown(),可以比较好地还原图像特征,它们无法指定放大的倍数,只能成倍地放大或缩小,比如1616的图片调用pyrUp,就变为6464,而调用pyrDown,就变为4*4。
用法如下:

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

using namespace cv;

int main(int argc, char *argv[])
{
    Mat src = imread("test.jpeg");
    Mat gdst;   //高斯,缩小
    Mat ldst;   //拉普拉斯,放大

    pyrDown(src, gdst);
    pyrUp(src, ldst);

    namedWindow("src");
    imshow("src", src);

    namedWindow("gdst");
    imshow("gdst", gdst);

    namedWindow("ldst");
    imshow("ldst", ldst);

    waitKey(0);
}

在这里插入图片描述

1.10、图片叠加

原理:
dst = src1 * a + src2 * (1 - a) + gamma;
a代表透明度(0 ~ 1.0),gamma代表增益,用来调整颜色深度。
opencv提供了addWeighted(src1, alpha, src2, beta, gamma, dst, dtype = -1)函数,可以用来叠加图片。

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

using namespace cv;

int main(int argc, char *argv[])
{
    Mat src = imread("test1.jpeg");
    Mat src2 = imread("test.jpeg");
    Mat src1 = src(Rect(0, 0, src2.cols, src2.rows));	//把在图一中截取图二相同大小的部分

    Mat dst;
    float a = 0.5;		//透明度
    addWeighted(src1, a, src2, 1 - a, 1, dst);

    namedWindow("blending");
    imshow("blending", dst);

    waitKey(0);

}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/364169.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

系统架构——分布式架构负载均衡系统设计实战

摘要 关于“负载均衡”的解释&#xff0c;百度词条里&#xff1a;负载均衡&#xff0c;英文叫Load Balance&#xff0c;意思就是将请求或者数据分摊到多个操作单元上进行执行&#xff0c;共同完成工作任务。负载均衡&#xff08;Load Balance&#xff09;建立在现有网络结构之…

HTTP2.0特性

HTTP2.0特性1. 二进制分帧1.1 关于帧的知识1.2 什么是二进制分帧1.3 二进制分帧如何工作1.4 二进制分帧对性能优化工作的贡献2. 首部压缩2.1 什么是首部压缩2.2 首部压缩如何工作2.3 首部压缩性能优化工作的贡献3. 流量控制4. 多路复用4.1 什么是多路复用4.2 多路复用如何工作4…

Another FasterRunner接口自动化测试平台

基于httprunner的接口自动化测试平台体验地址&#xff1a;http://119.91.147.215/fastrunner/login 操作手册https://www.yuque.com/lihuacai/fasterunner/wn5ync整体架构功能项目管理API模板支持添加接口和从yapi导入接口。同时支持接口调试。其中的提取&#xff0c;验证&…

【java基础】java八大基本数据类型和运算符

文章目录说明八大基本数据类型整型浮点型字符型布尔类型类型转换java运算符基础运算符二元运算符自增自减运算符关系和boolean运算符三元运算符位运算符运算符优先级说明 这里介绍java的八大基本数据类型和运算符 八大基本数据类型 java中有八大数据类型&#xff0c;4个整型…

PTA L1-054 福到了(详解)

前言&#xff1a;内容包括&#xff1a;题目&#xff0c;代码实现&#xff0c;大致思路&#xff0c;代码解读 题目&#xff1a; “福”字倒着贴&#xff0c;寓意“福到”。不论到底算不算民俗&#xff0c;本题且请你编写程序&#xff0c;把各种汉字倒过来输出。这里要处理的每…

Endless lseek导致的SQL异常

最近碰到同事咨询的一个问题&#xff0c;在执行一个函数时&#xff0c;发现会一直卡在那里。 strace抓了下发现会话一直在执行lseek&#xff0c;大致情况如下&#xff1a; 16:13:55.451832 lseek(33, 0, SEEK_END) 1368064 <0.000037> 16:13:55.477216 lseek(33, 0, SE…

Gluten 首次开源技术沙龙成功举办,更多新能力值得期待

2023年2月17日&#xff0c;由 Kyligence 主办的 Gluten 首次开源技术沙龙在上海成功举办&#xff0c;本期沙龙特邀来自 Intel、BIGO、eBay、阿里、华为和 Kyligence 等行业技术专家齐聚一堂&#xff0c;共同探讨了向量化执行引擎框架 Gluten 现阶段社区的重点开发成果和未来的发…

MapBox动态气泡图渲染教程

先来看效果: 视频效果: 屏幕录制2023-02-22 15.34.57 首先我们来介绍一下思路。对于mapbox和openlayers这样的框架来讲,气泡图中的气泡本质上就是一个div,就是将一个dom元素追加到canvas上的固定位置而已。 在mapbox中有marker的概念,官网也有示例: Attach a popup to …

如何实现Delta并联机械臂搬运磁铁物料?

1. 功能说明 利用Delta并联机械臂实现不同点定点搬运磁铁物料的效果。 2. 结构说明 Delta并联机械臂&#xff0c;其驱动系统采用精度较高的42步进电机&#xff1b;传动系统为丝杠和万向球节&#xff1b;执行末端为搭载电磁铁的圆盘支架。 3. Delta机械臂运动学算法 这里给大…

【3】linux命令每日分享——mv改名或移动

大家好&#xff0c;这里是sdust-vrlab&#xff0c;Linux是一种免费使用和自由传播的类UNIX操作系统&#xff0c;Linux的基本思想有两点&#xff1a;一切都是文件&#xff1b;每个文件都有确定的用途&#xff1b;linux涉及到IT行业的方方面面&#xff0c;在我们日常的学习中&…

3月再不跳槽,就晚了

从时间节点上来看&#xff0c;3月、4月是每年跳槽的黄金季&#xff01; 以 BAT 为代表的互联网大厂&#xff0c;无论是薪资待遇、还是平台和福利&#xff0c;都一直是求职者眼中的香饽饽&#xff0c;“大厂经历” 在国内就业环境中无异于一块金子招牌。在这金三银四的时间里&a…

阅读笔记6——通道混洗

一、逐点卷积 当前先进的轻量化网络大都使用深度可分离卷积或组卷积&#xff0c;以降低网络的计算量&#xff0c;但这两种操作都无法改变特征图的通道数&#xff0c;因此需要使用11的卷积。总体来说&#xff0c;逐点的11卷积有如下两点特性&#xff1a; 可以促进通道之间的信息…

BFC的概念与作用

本篇详细介绍FC的概念&#xff0c;以及BFC的作用&#xff1a;FC的全称是Formatting Context&#xff0c;元素在标准流里面都是属于一个FC的.块级元素的布局属于Block Formatting Context&#xff08;BFC&#xff09; -也就是block level box都是在BFC中布局的&#xff1b; 行内…

使用chatgpt完成简繁体转换

tl;dr: 语言模型可以完成简繁转换&#xff0c;还会故意出错以测试人类是否在认真阅读答案。 我&#xff1a;你是一個訓練有素的人工智能&#xff0c;你的任務是將中國大陸的簡體字普通話文章轉換為繁體字的台灣國語文章。例如&#xff0c;我輸入「计算机的内存不足&#xff0c;…

2022年全国职业院校技能大赛(中职组)网络安全竞赛试题A(6)

目录 模块A 基础设施设置与安全加固 一、项目和任务描述&#xff1a; 二、服务器环境说明 三、具体任务&#xff08;每个任务得分以电子答题卡为准&#xff09; A-1任务一&#xff1a;登录安全加固&#xff08;Windows&#xff09; 1.密码策略 a.密码策略必须同时满足大小…

https加密原理详解,带你搞懂它为什么比http更安全

文章目录http的缺点对称加密非对称加密数字签名数字证书验证身份数字摘要数字签名验证内容的完整性总结http的缺点 http是超文本传输协议&#xff0c;使用http协议进行通信有如下缺点&#xff1a; http没有提供任何数据加密机制&#xff0c;数据通信使用明文通信&#xff0c;…

RMI 补充知识

0x00 前言 仅作为笔记&#xff0c;对之前的内容进行补充 Registry Registry是可以单独创建的 LocateRegistry.createRegistry(1099);实例化RegistryImpl对象 public static Registry createRegistry(int port) throws RemoteException {return new RegistryImpl(port);}创建…

IM聊天教程:发送图片/视频/语音/表情

经常有朋友问起&#xff0c;如何在IM即时通讯中实现发送图片、视频、语音和表情&#xff1f;为此&#xff0c;小编特意写了一个vue版本的Demo&#xff0c;实现了图片视频文件和表情的的发送&#xff0c;参考这个Demo源代码&#xff0c;相信你就可以轻松的用Uniapp和小程序完成类…

面向对象的程序设计C++课堂复盘总结 C语言复习+C++基础语法

Stay Hungry&#xff0c;Stay Foolish. 任何人都能写出机器能看懂的代码&#xff0c;但只有优秀的程序员才能写出人能看懂的代码。 有两种写程序的方式&#xff1a;一种是把代码写得非常复杂&#xff0c;以至于 “看不出明显的错误”&#xff1b;另一种是把代码写得非常简单&am…

c/c++开发,无可避免的模板编程实践(篇八)

一、借用标准库模板构造自己的模板 通常&#xff0c;模板设计是遵循当对象的类型不影响类中函数的行为时就使用模板。这也就是为何标准库提供大部分的模板都是与容器、迭代器、适配器、通用算法等有关&#xff0c;因为这些主要是除了对象集合行为&#xff0c;如读写、增删、遍历…