从根本上说,一张图像时一个由数值组成的矩阵,这也是Opencv2用cv::Mat这个数据结构来表示图像的原因。矩阵的每个元素代表一个像素,对于灰度图像,像素有8为无符号数来表示,其中0代表黑色,255代表白色;对于彩色图象,每个像素需要三个这样的8位无符号数来表示三个颜色通道(红蓝绿)。此时矩阵的元素是一个三元数。

为了存取矩阵元素,你需要在代码中指定元素所在的行和列。程序会返回相应的元素。如果图像是单通道的,返回值是单个数值;如果图像时多通道的,返回值怎是一组向量(Vector)。


我们通过一个简单的函数俩演示直接存取像素值,该函数会在图像中加入盐噪点(随机的部分像素设置为白色或黑色),即模拟像素值丢失的情况。


一、代码


#include 
 <iostream>
 
#include 
 <opencv2\core\core.hpp>
 
#include 
 <opencv2\highgui\highgui.hpp>
 
using 
 namespace 
 std;
 
using 
 namespace 
 cv;
 
void 
 salt( 
 Mat 
 & 
 image 
 , 
 int 
 n 
 )
 
{
 
        
 for 
 ( 
 int 
 k = 0; k < 
 n 
 ; k++)
 
       {
 
               
 //图像的行号为j,列号为i
 
               
 int 
 i = rand()% 
 image 
 .cols;
 
               
 int 
 j = rand() % 
 image 
 .rows;
 
               
 //如果通道数是1,即为灰度图;如果通道数为3,即为彩色图
 
               
 if 
 ( 
 image 
 .channels() == 1) {
 
                      
 image 
 .at< 
 uchar 
 >(j, i) = 255;
 
              }
 
               
 else 
 if 
 ( 
 image 
 .channels() == 3) {
 
                      
 image 
 .at< 
 Vec3b 
 >(j, i) 
 [ 
 0 
 ] 
 = 255;
 
                      
 image 
 .at< 
 Vec3b 
 >(j, i) 
 [ 
 1 
 ] 
 = 255;
 
                      
 image 
 .at< 
 Vec3b 
 >(j, i) 
 [ 
 2 
 ] 
 = 255;
 
              }
 
       }
 
}
 
int 
 main( 
 int 
 argc 
 , 
 char 
 ** 
 argv 
 )
 
{
 
        
 Mat 
 srcImage = imread( 
 "1.jpg" 
 );
 
        
 if 
 (!srcImage.data)
 
       {
 
              cout 
 << 
 "“1.jpg”读取失败!" 
 << 
 endl;
 
               
 return 
 0;
 
       }
 
       salt(srcImage, 3000);
 
       namedWindow( 
 "Image" 
 );
 
       imshow( 
 "Image" 
 , srcImage);
 
       waitKey(0);
 
        
 return 
 0;
 
}


二、分析



类cv::Mat有若干成员函数可以获取图像属性。公有成员变量 cols 和 rows 给出了图像的宽和高。成员函数 at( int y, int x) 可以用来存放图像元素。但必须在编译期间知道图像的数据类型,因为 cv::Mat 可以存放任意的数据类型的元素。这也是这个函数用模板函数来实现的原因。这也意味着,当调用该函数时,你需要使用以下方式指定数据类型:



image.at<uchar>(j,i)=255;


指定的数据类型一定和矩阵中的数据类型相符合。at方法本身不会进行任何数据类型转换。



对于彩色图像,每个像素有三个通道,一个包含彩色图像的cv::Mat 会返回三个8位数组成的向量。opencv将此向量定义为cv::Vec3b,即由三个unsigned char组成的向量,所以存取彩色图像像素的代码写成以下形式:


image.at<cv::Vec3b>(j, i)[channel]= value ;


三、扩展



cv::Mat 成员函数有时候比较麻烦,因为返回值的类型必须通过在调用时通过模板参数指定。因此,opencv提供了类cv::Mat_ ,它是cv::Mat的一个字类,此类的指针或引用可以直接进行相互类型转换。该类重载了操作符():


cv::Mat_ <uchar> im2=image; //im2指向image
 
 
im2(50,100)=0 ; //存取第50行,100列



四、测试结果



python opencv读取图像像素值 opencv获取像素值_数据类型