4--OpenCV:图像像素的读写&像素运算

本文介绍了OpenCV中图像像素的读写操作,包括uchar类型和Vec系列,以及如何通过数组方式和指针方式访问像素。详细讲解了如何进行负片处理,并展示了使用at和ptr成员函数的例子。此外,还讨论了OpenCV中的像素算术运算,如加法、减法、乘法、除法和混合运算,并提供了相关函数的使用示例。最后,探讨了位运算,包括位与、位或、非运算和异或运算,通过图像实例展示了这些操作的效果。
摘要由CSDN通过智能技术生成

opencv图像像素读写操作

常用类型介绍

  • uchar类型

typedef unsigned uint;
typedef signed char schar;
typedef unsigned char uchar;
typedef unsigned short ushort;
  • Vec系列

    Vec+数字+字母: C++STL vector容器类似

    • 数字: Vec 的长度

    • 字母: 类型

      • b: uchar

      • s:short

      • w: ushort

      • i: int

      • f:float

      • d:double

typedef Vec<uchar, 2> Vec2b;
typedef Vec<uchar, 3> Vec3b;
typedef Vec<uchar, 4> Vec4b;
​
typedef Vec<short, 2> Vec2s;
typedef Vec<short, 3> Vec3s;
typedef Vec<short, 4> Vec4s;
​
typedef Vec<ushort, 2> Vec2w;
typedef Vec<ushort, 3> Vec3w;
typedef Vec<ushort, 4> Vec4w;
​
typedef Vec<int, 2> Vec2i;
typedef Vec<int, 3> Vec3i;
typedef Vec<int, 4> Vec4i;
typedef Vec<int, 6> Vec6i;
typedef Vec<int, 8> Vec8i;
​
typedef Vec<float, 2> Vec2f;
typedef Vec<float, 3> Vec3f;
typedef Vec<float, 4> Vec4f;
typedef Vec<float, 6> Vec6f;
​
typedef Vec<double, 2> Vec2d;
typedef Vec<double, 3> Vec3d;
typedef Vec<double, 4> Vec4d;
typedef Vec<double, 6> Vec6d;

图像的像素读写

数组方式读写

注意:①at方法的使用,是Mat中的模板函数,需要实例化,<uchar>(unsigned char---->8个位都是用来存储相关的像素信息),然后传入x,y坐标即可。

        其返回值是引用类型,所以才有了下面的负片处理

          ②Mat中channels()方法获取图片的通道数,是一维的(黑白)还是三维的(rgb)

          ③注意dims=3的情况,如何接收pixel值的?--->Vec3b类型的容器接收。

int dims = img.channels();      //得到图片通道数
for (int i = 0; i < img.rows; i++) 
{
    for (int j = 0; j < img.cols; j++) 
    {
        if (dims == 1) 
        {
            //单通道图像像素点获取
            int pixel = img.at<uchar>(i, j);
            img.at<uchar>(i, j) = 255 - pixel;      //负片处理
        }
        if (dims == 3) 
        {
            //三通道图像像素点获取
            Vec3b bgr = img.at<Vec3b>(i, j);
            //负片处理
            img.at<Vec3b>(i, j)[0] = 255 - bgr[0];
            img.at<Vec3b>(i, j)[1] = 255 - bgr[1];
            img.at<Vec3b>(i, j)[2] = 255 - bgr[2];
        }
    }
}

指针方式读写

注意:Mat中的成员函数ptr用uchar实例化之后,传入要获取的行数,即可。

//二维数组-->一级指针访问二维数组方式
int dims = img.channels();
for (int i = 0; i < img.rows; i++) 
{
    //Mat中有一个ptr成员函数,获取当前i行的指针
    uchar* current_row = img.ptr<uchar>(i);
    for (int j = 0; j < img.cols; j++) 
    {
        if (dims == 1) 
        {
            int pixel = *current_row;      //current_row[j];
            *current_row++ = 255 - pixel;  //做一个横向移动
        }
        if (dims == 3)
        {
            Vec3b bgr = img.at<Vec3b>(i, j);
            *current_row++ = 255 - *current_row;
            *current_row++ = 255 - *current_row;
            *current_row++ = 255 - *current_row;
        }
    }
}

        注意:*p++中*和++的运算优先级相同,自右向左的运算顺序,

                                所以先++(指针的指向先发生改变) 

完整案例

#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
class ImgVisitPixel 
{
public:
    ImgVisitPixel(int type = IMREAD_UNCHANGED) :img(imread("mm.jpg",type)) {}
    void Show(string wName) 
    {
        imshow(wName, img);
        moveWindow(wName, 600, 300);
        waitKey(0);
    }
    void Visit_By_Array();
    void Visit_By_Point();
protected:
    Mat img;
};
​
void ImgVisitPixel::Visit_By_Array()
{
    int dims = img.channels();      //得到图片通道数
    for (int i = 0; i < img.rows; i++) 
    {
        for (int j = 0; j < img.cols; j++) 
        {
            if (dims == 1) 
            {
                //单通道图像像素点获取
                int pixel = img.at<uchar>(i, j);
                img.at<uchar>(i, j) = 255 - pixel;      //负片处理
            }
            if (dims == 3) 
            {
                //三通道图像像素点获取
                Vec3b bgr = img.at<Vec3b>(i, j);
                //负片处理
                img.at<Vec3b>(i, j)[0] = 255 - bgr[0];
                img.at<Vec3b>(i, j)[1] = 255 - bgr[1];
                img.at<Vec3b>(i, j)[2] = 255 - bgr[2];
            }
        }
    }
}
​
void ImgVisitPixel::Visit_By_Point()
{
    int dims = img.channels();
    for (int i = 0; i < img.rows; i++) 
    {
        //Mat中有一个ptr成员函数,获取当前i行的指针
        uchar* current_row = img.ptr<uchar>(i);
        for (int j = 0; j < img.cols; j++) 
        {
            if (dims == 1) 
            {
                int pixel = *current_row;      //current_row[j];
                *current_row++ = 255 - pixel;  //做一个横向移动
            }
            if (dims == 3)
            {
                Vec3b bgr = img.at<Vec3b>(i, j);
                *current_row++ = 255 - *current_row;
                *current_row++ = 255 - *current_row;
                *current_row++ = 255 - *current_row;
            }
        }
    }
​
}
​
int main() 
{
    ImgVisitPixel* pImg = new ImgVisitPixel;
    pImg->Show("原图");
    pImg->Visit_By_Array();
    pImg->Show("第一次负片操作");
    pImg->Visit_By_Point();
    pImg->Show("第二次负片操作");
    return 0;
}

像素读写注意点

在读取到像素点的时候,做一些算数运算,一定要注意颜色范围问题小心溢出,针对溢出,opencv提供一个转换防止溢出

saturate_cast<要转换的类型>(要转换的数据)

  • 小于0 等于0

  • 大于255 直接等于255

img.at<Vec3b>(i, j)[0] =saturate_cast<uchar>(bgr[0]+100);
img.at<Vec3b>(i, j)[1] = saturate_cast<uchar>(bgr[1] + 100);
img.at<Vec3b>(i, j)[2] = saturate_cast<uchar>(bgr[2] + 100);

opencv图像像素运算

注意:参与算术运算图像的数据类型、通道数目、大小必须相同!!!

算术运算

加法:add

void add(InputArray src1, InputArray src2, OutputArray dst,InputArray mask = noArray(), int dtype = -1);
/*******************************************************************
*           src1:   输入图1
*           src2:   输入图2
*           dst:    输出图
*           mask:   遮罩像素  可有可无
*           dtype:  输出图深度 可有可无
*********************************************************************/

减法:subtract

void subtract(InputArray src1,InputArray src2,OutputArray dst,InputArray mask = noArray(),int dtype = -1);
/*******************************************************************
*           src1:   输入图1
*           src2:   输入图2
*           dst:    输出图
*           mask:   遮罩像素  可有可无
*           dtype:  输出图深度 可有可无
*********************************************************************/

乘法:multiply

void multiply(InputArray src1, InputArray src2,OutputArray dst, double scale = 1, int dtype = -1);
/*******************************************************************
*           src1:   输入图1
*           src2:   输入图2
*           dst:    输出图
*           scale:  缩放因子,即在src1*src2的基础上再乘scale
*           dtype:  输出图深度 可有可无
*********************************************************************/

除法:divide

void divide(InputArray src1, InputArray src2, OutputArray dst,double scale = 1, int dtype = -1);
/*******************************************************************
*           src1:   输入图1
*           src2:   输入图2
*           dst:    输出图
*           scale:  缩放因子,即在src1*src2的基础上再乘scale
*           dtype:  输出图深度 可有可无
*********************************************************************/

混合运算:addWeighted

dst = α · img1 + β · img2 + γ

void addWeighted(InputArray s1,double a,InputArray s2,double b,double gamma,OutputArray d,int dtype = -1);
/*******************************************************************
*           s1:     输入图1
*           a:       输入图占比  α
*           s2:     输入图2
*           b:      输入图2占比  β
*           gamma:  附加值,结果基础上再加+gamma   γ  
*           dst:    输出图
*           dtype:  输出图深度 可有可无
*********************************************************************/

综合代码

#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
class ImgOpreations 
{
public:
    ImgOpreations() :img1(imread("mm.jpg")), img2(imread("text.jpg")) 
    {
        result = Mat::zeros(img1.size(), img2.type());      //存储的图像一定要初始化
    }
    void testAdd(string wName="Add")
    {
        add(img1, img2, result);
        imshow(wName, result);
        waitKey(0);
    }
    void testSub(string wName="Sub")
    {
        subtract(img1, img2, result);
        imshow(wName, result);
        waitKey(0);
    }
    void testMul(string wName="Mul")
    {
        multiply(img1, img2, result);
        imshow(wName, result);
        waitKey(0);
    }
    void testDivide(string wName = "Div") 
    {
        divide(img1, img2, result);
        imshow(wName, result);
        waitKey(0);
    }
    //dst = α · img1 + β · img2 + γ  
    void testAddWeighted(string wName = "AddWeighted") 
    {
        addWeighted(img1, 0.6, img2, 0.4, 0, result);
        imshow(wName, result);
        waitKey(0);
    }
​
protected:
    Mat img1;
    Mat img2;
    Mat result;
};
​
​
int main() 
{
    ImgOpreations* pImg = new ImgOpreations;
    pImg->testAdd();
    pImg->testSub();
    pImg->testMul();
    pImg->testDivide();
    pImg->testAddWeighted();
    return 0;
}

位运算 

位与

void bitwise_and(InputArray src1, InputArray src2,,OutputArray dst, InputArray mask = noArray());
/*******************************************************************
*           src1:   输入图1
*           src2:   输入图2
*           dst:    输出图
*           mask:   遮罩像素  可有可无
*********************************************************************/

位或

void bitwise_or(InputArray src1, InputArray src2, OutputArray dst, InputArray mask = noArray());
/*******************************************************************
*           src1:   输入图1
*           src2:   输入图2
*           dst:    输出图
*           mask:   遮罩像素  可有可无
*********************************************************************/

非运算

void bitwise_not(InputArray src, OutputArray dst,InputArray mask = noArray());
/*******************************************************************
*           src1:   输入图1
*           dst:    输出图
*           mask:   遮罩像素  可有可无
*********************************************************************/

异或运算

void bitwise_xor(InputArray src1, InputArray src2,OutputArray dst, InputArray mask = noArray());
/*******************************************************************
*           src1:   输入图1
*           src2:   输入图2
*           dst:    输出图
*           mask:   遮罩像素  可有可无
*********************************************************************/

综合代码:图像位运算用图片

#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
class BitWise 
{
public:
    BitWise() :img1(imread("mm.jpg")), img2(imread("text.jpg")) {}
    void Show() 
    {
        imshow("mm", img1);
        imshow("text", img2);
    }
    void BitOpreations() 
    {
        Mat myand, myor, myxor, mynot;
        bitwise_and(img1, img2, myand);
        bitwise_or(img1, img2, myor);
        bitwise_not(img1, mynot);
        bitwise_xor(img1, img2, myxor);
            
        imshow("and", myand);
        imshow("or", myor);
        imshow("xor", myxor);
        imshow("not", mynot);
        waitKey(0);
    }
protected:
    Mat img1;
    Mat img2;
};
int main() 
{
    BitWise* pImg = new BitWise;
    pImg->Show();
    pImg->BitOpreations();
    return 0;
}

图像位运算用自绘图图形

注意:       

        ①函数Scalar的使用,传入一个参数就是单通道,三个参数就是RGB

        ②注意构造函数的写法,在Mat类型的img中利用Rect函数进行绘制。

#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
class BitWise 
{
public:
    BitWise() :img1(Mat(200,200,CV_8UC1)), img2(Mat(200,200,CV_8UC1)) 
    {
        //Rect绘制矩形(左上角坐标 和绘制矩形宽度和高度)
        img1(Rect(50, 50, 100, 100)) = Scalar(255);
        img2(Rect(100, 100, 100, 100)) = Scalar(255);
    }
    void Show() 
    {
        imshow("mm", img1);
        imshow("text", img2);
        waitKey(0);
    }
    void BitOpreations() 
    {
        Mat myand, myor, myxor, mynot;
        bitwise_and(img1, img2, myand);
        bitwise_or(img1, img2, myor);
        bitwise_not(img1, mynot);
        bitwise_xor(img1, img2, myxor);
            
        imshow("and", myand);
        imshow("or", myor);
        imshow("xor", myxor);
        imshow("not", mynot);
        waitKey(0);
    }
protected:
    Mat img1;
    Mat img2;
};
int main() 
{
    BitWise* pImg = new BitWise;
    pImg->Show();
    pImg->BitOpreations();
    return 0;
}

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

_Ocean__

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

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

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

打赏作者

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

抵扣说明:

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

余额充值