尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

opencv 学习: 05 像素处理

opencv 学习: 05 像素处理
📅 发布时间:2026/6/20 0:45:28

1.像素操作

图像处理归根到底是对图像像素的操作。

像素操作少不了对像素的遍历,而且要高效的遍历,因为像素数据量通常非常巨大。

以灰度图为例,其实一张图片就是一个矩阵,矩阵中的每个数字都表示一个像素。

灰度图,是一张由只包含明暗程度信息的像素组成的。通常,如果每个像素是unsigned 8-bit 格式,则 0 代表纯黑,255 代表纯白。

彩色图,是由红绿蓝三个色彩元素组成一个像素。每个像素中的各个色彩元素值,表示各自色彩的亮度。

这是由人的视觉系统决定的。

通常,8位已经足够,也有一些特殊应用需要16位(例如医学成像)。OpenCV还允许用其他类型的像素类型,创建矩阵(或图像),例如,整数(CV_32U 或 CV_32S)和浮点(CV_32F)数字。

这对于存储非常有用,例如,在某些图像处理任务中存储中间值。

大多数运算可以应用于任何类型的矩阵;另一些则需要特定类型的工作,仅使用给定数量的通道。因此,为了避免常见的编程错误,很好地理解函数或方法的前提条件是必不可少的。

1.1 操作像素值

只需要指明像素的行列位置,既可以获取到对应像素的值,对于灰度图就是一个数值,对于多通道的彩色图,将返回一个vector.

为了只管展示对像素的操作,简单实现一个椒盐噪声方法。

顾名思义,椒盐噪声是一种特殊类型的噪声,一些随机选择的像素被白色或黑色像素所取代。这种类型的噪声可能发生在故障通信中,某些像素值在传输过程中丢失。例子中,只是简单随机选中一些像素值进行赋值。

void salt(cv::Mat& image, int amount) {
int rows,cols;
for (size_t i = 0; i < amount; i++)
{
//std::rand() function returns a value between 0 and RAND_MAX
rows = rand() % image.rows;
cols = rand() % image.cols;
if (image.channels() == 1) {//灰度图像
image.at<uchar>(rows, cols) = 255;}else { //彩色图像image.at<cv::Vec3b>(rows, cols)[0] = 255;image.at<cv::Vec3b>(rows, cols)[1] = 255;image.at<cv::Vec3b>(rows, cols)[2] = 255;}}}

cv::Mat 包含多个对图片属性进行读写的方法。

对于公有的成员变量,如 rows 、cols 可以直接获取图片的高度和宽度。

对于像素的读写,可使用 at(int y, int x) 方法。但是,方法返回的类型必须在编译时已知,因为由于 cv:: mat 可以保存任何类型的元素,因此程序员需要指定预期的返回类型。

这也是为什么 at 方法被实现为 模板方法。所以,需要在调用时,指明类型:

image.at<uchar>(row, col) = 255;

注意:at 方法不会进行任何类型转换。所以,确保与像素类型匹配是编程人员的职责。

彩色图像中,每个像素有RGB三个分量。因此,cv::Mat 会返回包含三个 8-bit 值的 vector。 opencv 为这个类型定义了一个专用类型 cv::Vec3b . 对应的赋值语句就写成了如下方式:

//channel 代表0、1、2某个通道 
//opencv 以 BGR 的顺序存储数据,通道 0 代表 Blue 通道,以此类推。
image.at<cv::Vec3b>(row,col)[channel] = value;

对于两元素和四元素向量(cv::Vec2bandcv::Vec4b)以及其他元素类型也存在类似的向量类型。例如,对于双元素浮点向量,类型名的最后一个字母将被替换为 f , 即 cv::Vec2f 。在 short 类型的情况下,最后一个字母被替换为 s,对于 integer 被替换为 i,对于双精度浮点向量被替换为 d。

所有这些类型都是使用v::Vec<T,N>模板类定义的,其中 T 是类型,N 是 vector 元素的个数。

最后,你可能会发现图像传参,使用的是值传参方式。

这涉及前面的知识,对图像的普通复制时,它们仍然共享相同的图像数据。所以,当在函数内修改图片的内容时,不一定要通过引用来传输图片。顺便提一下,按值传递参数通常使编译器更容易进行代码优化。

1.2 cv::Mat_ 模板类

使用C++模板定义 cv::Mat ,使其变得通用。

使用 cv::Mat 的 at 方法,有时会很麻烦,因为必须在每次调用中将返回的类型,指定为模板参数。

在矩阵类型已知的情况下,以使用 cv::Mat_ ,它是cv::Mat的模板子类。这个类定义了一些额外的方法,但没有新的数据属性,因此指向一个类的指针或引用,可以直接转换到另一个类。在这些额外的方法中,有operator(),它允许直接访问矩阵元素。因此,如果一个图像是对应于 uchar 类型的 cv::Mat 变量,那么可以写下面的代码:

//使用 cv::Mat_ 模板
cv::Mat_<uchar> im(image);// row 100, col 200 的像素被赋值 0im(100,200) = 0;

由于在创建变量时声明了 cv::Mat_ 元素的类型,因此 operator() 方法在编译时就知道要返回哪种类型。这使得代码更简洁,与at 方法效果完全相同。

完整代码:

#include <iostream>#include <opencv2/opencv.hpp>// 盐噪声// 值传图像,因为是引用计数的方式,相当于浅拷贝,其实就会改变原图像void salt(cv::Mat/*&*/ image, int amount){int row, col;for (size_t i = 0; i < amount; i++){// std::rand() function returns a value between 0 and RAND_MAXrow = rand() % image.rows;col = rand() % image.cols;if (image.channels() == 1){ // 灰度图像image.at<uchar>(row, col) = 255;}else{ // 彩色图像image.at<cv::Vec3b>(row, col)[0] = 255;image.at<cv::Vec3b>(row, col)[1] = 255;image.at<cv::Vec3b>(row, col)[2] = 255;}}}// 椒噪声 尝试使用cv::Mat_<>void pepper(cv::Mat image, int amount){int row, col;if (image.channels() == 1){ // 灰度图像cv::Mat_<uchar> temp(image);for (size_t i = 0; i < amount; i++){row = rand() % image.rows;col = rand() % image.cols;temp(row, col) = 0;}}else{ // 彩色图像cv::Mat_<cv::Vec3b> temp(image);for (size_t i = 0; i < amount; i++){row = rand() % image.rows;col = rand() % image.cols;temp(row, col) = cv::Vec3b(0, 0, 0);}}}int main(int argc, char *argv[]){// 检查命令行参数if (argc != 4){std::cerr << "Usage: " << argv[0] << " <input_image> <noise_rate:0.0 ~ 1.0> <output_image>" << std::endl;return -1;}// 读取输入图像和logo图像cv::Mat input_image = cv::imread(argv[1]);// 检查输入图像和logo图像是否成功读取if (input_image.empty()){std::cerr << "Error: Could not open or find input image" << std::endl;}cv::namedWindow("input_image", cv::WINDOW_NORMAL);cv::imshow("input_image", input_image);cv::waitKey(0);float noise_rate = std::stof(argv[2]);if (noise_rate < 0 || noise_rate > 1){std::cerr << "Error: noise_rate must be between 0.0 and 1.0" << std::endl;return -1;}// 细想,其实也不严谨,并不会严格贴近指定的噪声数量。可能存在重复赋值的问题// 只是简单控制下噪声点的数量而已salt(input_image, input_image.total() * noise_rate);pepper(input_image, input_image.total() * noise_rate);cv::imwrite(argv[3], input_image);cv::namedWindow("output_image", cv::WINDOW_NORMAL);cv::imshow("output_image", input_image);cv::waitKey(0);return 0;}

效果:会增加许多的噪点请添加图片描述

相关新闻

  • 正则表达式匹配 IP 地址
  • Linux驱动开发与Android驱动创建
  • 2025东莞艺立鞋服科技实力解析:六家顶尖鞋类设计培训与打版技术创业班深度排名

最新新闻

  • Mac上的Windows启动盘制作革命:WinDiskWriter全方位指南
  • 2026行业内优秀非法吸收公众存款罪刑事律师口碑推荐 - 品牌排行榜
  • 实战测试10款降AI率软件:帮你锁定达标神器
  • 解析2026年武汉会展场地对接服务:如何甄选兼具资源与实力的靠谱合作伙伴 - 品牌鉴赏官2026
  • JavaScript DXF Writer终极指南:在浏览器中生成CAD图纸的完整教程
  • 北京大理石修补推荐良匠千艺2026口碑榜 - 我叫一

日新闻

  • 信任的进化:技术实现详解——如何用JavaScript构建博弈论模拟器
  • Terrakube自定义工作流:如何集成OPA、Infracost等工具扩展IaC能力
  • grunt-concurrent快速入门:5分钟学会并行运行Grunt任务

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号