4.opencv由浅入深--图像像素相关操作

4.opencv由浅入深–图像像素相关操作

1.图像基础

1、模拟图像:连续图像 通过某种物理量(如光、电等)的强弱变化来记录图像亮度信息,是连续变化的。
2、数字图像:计算机采用0/1编码的系统,数字图像也是利用0/1来记录信息,我们平常接触的图像都是8位数图像包含0-255灰度。像素点是组成数字图像的最小单位,对于不同类型的图像,像素点数据不一样。
数字图像分类:二值图像、灰度图像、彩色图像。
二值图像:每个像素取值0/1。
灰度图像:每个像素8位 0-255 (没有三个通道,只有一个通道,表示亮度就可以)。
彩色图像:每个像素由R G B 三个分量表示,每个分量0-255,因此单独拿出一个分量就是一个灰度图,每一像素的颜色需由R,G、B三个分量来表示,M,N分别表示图像的行列数,三个MxN的二维矩阵分别表示各个像素的R,G、B三个颜色分量。

2.opencv内部定义的数据类型

在操作像素点之前,先熟悉一下opencv定义常用数据类型

在include\opencv2\core\types.hpp文件中
typedef Point_<int> Point2i;
typedef Point_<int64> Point2l;
typedef Point_<float> Point2f;
typedef Point_<double> Point2d;
typedef Point2i Point;

typedef Point3_<int> Point3i;
typedef Point3_<float> Point3f;
typedef Point3_<double> Point3d;

typedef Size_<int> Size2i;
typedef Size_<int64> Size2l;
typedef Size_<float> Size2f;
typedef Size_<double> Size2d;
typedef Size2i Size;

typedef Rect_<int> Rect2i;
typedef Rect_<float> Rect2f;
typedef Rect_<double> Rect2d;
typedef Rect2i Rect;

typedef Scalar_<double> Scalar;

在modules\core\include\opencv2\core\matx.hpp文件中
typedef Matx<float, 1, 2> Matx12f;
typedef Matx<double, 1, 2> Matx12d;
typedef Matx<float, 1, 3> Matx13f;
typedef Matx<double, 1, 3> Matx13d;
typedef Matx<float, 1, 4> Matx14f;
typedef Matx<double, 1, 4> Matx14d;
typedef Matx<float, 1, 6> Matx16f;
typedef Matx<double, 1, 6> Matx16d;

typedef Matx<float, 2, 1> Matx21f;
typedef Matx<double, 2, 1> Matx21d;
typedef Matx<float, 3, 1> Matx31f;
typedef Matx<double, 3, 1> Matx31d;
typedef Matx<float, 4, 1> Matx41f;
typedef Matx<double, 4, 1> Matx41d;
typedef Matx<float, 6, 1> Matx61f;
typedef Matx<double, 6, 1> Matx61d;

typedef Matx<float, 2, 2> Matx22f;
typedef Matx<double, 2, 2> Matx22d;
typedef Matx<float, 2, 3> Matx23f;
typedef Matx<double, 2, 3> Matx23d;
typedef Matx<float, 3, 2> Matx32f;
typedef Matx<double, 3, 2> Matx32d;

typedef Matx<float, 3, 3> Matx33f;
typedef Matx<double, 3, 3> Matx33d;

typedef Matx<float, 3, 4> Matx34f;
typedef Matx<double, 3, 4> Matx34d;
typedef Matx<float, 4, 3> Matx43f;
typedef Matx<double, 4, 3> Matx43d;

typedef Matx<float, 4, 4> Matx44f;
typedef Matx<double, 4, 4> Matx44d;
typedef Matx<float, 6, 6> Matx66f;
typedef Matx<double, 6, 6> Matx66d;

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;

3.opencv中像素操作

像素点在不同图像中表示方式不一样,分为单通道和多通道。单通道中像素点是一个无符号的8位整数,多通道中像素点由每个通道组成的向量,每个通道是一个无符号的8位整数。

opencv有3种方式可以操作像素:
1、用at遍历图像元素,即为通过成员函数at访问。
使用at方法访问元素需要提供行号和列号,以及元素的类型.
// 单通道图像
img.at<uchar>(rows, cols) = 200;
// 三通道图像
img.at<Vec3b>(rows, cols) = Vec3b(100, 100, 100);

2、用指针遍历图像元素,通过成员函数ptr访问。
用指针遍历图像元素更加高效。
// 单通道图像
uchar* p = img.ptr<uchar>(rows, cols);
*p = 200;
// 三通道图像
Vec3b* p = img.ptr<Vec3b>(rows, cols);
p[0] = 100; 
p[1] = 100; 
p[2] = 100; 

3、用迭代器变量图像像素。
// 单通道图像
Mat_<uchar>::iterator begin = img.begin<uchar>();
Mat_<uchar>::iterator end = img.end<uchar>();
for (auto it = begin; it != end; it++)
{
    *it = 200;
}
// 三通道图像
Mat_<Vec3b>::iterator begin = img.begin<Vec3b>();
Mat_<Vec3b>::iterator end = img.end<Vec3b>();
for (auto it = begin; it != end; it++)
{
    *it = Vec3b(200, 200, 200);
}
或者
// 单通道图像
MatIterator_<uchar> begin = img.begin<uchar>(), end = img.end<uchar>();
for (auto it = begin; it != end; it++)
{
    *it = 200;
}
// 三通道图像
MatIterator_<Vec3b> begin = img.begin<Vec3b>(), end = img.end<Vec3b>();
for (auto it = begin; it != end; it++)
{
    *it = Vec3b(200, 200, 200);
}

4.opencv像素操作实例

#include <iostream>

#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main()
{
    // 单通道图像 白色图像
    Mat img1 = Mat(400, 500, CV_8UC1, Scalar(255));
    // 三通道图像 白色图像
    Mat img3 = Mat(400, 500, CV_8UC3, Scalar(255,255,255));
    // 显示原始图像
    imshow("单通道图像 原始图:", img1);
    imshow("三通道图像 原始图:", img3);

    // 1.通过at访问 修改为灰色图像
    for (int rows = 0; rows < img1.rows; rows++)
    {
        for (int cols = 0; cols < img1.cols; cols++)
        {
            img1.at<uchar>(rows, cols) = 100;
        }
    }
    imshow("单通道图像 灰色图:", img1);
    for (int rows = 0; rows < img3.rows; rows++)
    {
        for (int cols = 0; cols < img3.cols; cols++)
        {
            img3.at<Vec3b>(rows, cols) = Vec3b(100, 100, 100);
        }
    }
    imshow("三通道图像 灰色图:", img3);
    
    // 2.通过指针ptr访问
    for (int rows = 0; rows < img1.rows; rows++)
    {
        for (int cols = 0; cols < img3.cols; cols++)
        {
            uchar* p = img1.ptr<uchar>(rows, cols);
            *p = 0;
        }
    }
    imshow("单通道图像 黑色图:", img1);
    for (int rows = 0; rows < img3.rows; rows++)
    {
        for (int cols = 0; cols < img3.cols; cols++)
        {
            Vec3b* p = img3.ptr<Vec3b>(rows, cols);
            p[0] = 0;
            p[1] = 0;
            p[2] = 0;
        }
    }
    imshow("三通道图像 黑色图:", img3);

    // 3.通过迭代器访问
    //Mat_<uchar>::iterator begin1 = img1.begin<uchar>();
    //Mat_<uchar>::iterator end1 = img1.end<uchar>();
    //for (auto it = begin1; it != end1; it++)
    //{
    //    *it = 200;
    //}
    MatIterator_<uchar> begin1 = img1.begin<uchar>(), end1 = img1.end<uchar>();
    for (auto it = begin1; it != end1; it++)
    {
        *it = 200;
    }
    imshow("单通道图像 灰白图:", img1);
    //Mat_<Vec3b>::iterator begin3 = img3.begin<Vec3b>();
    //Mat_<Vec3b>::iterator end3 = img3.end<Vec3b>();
    //for (auto it = begin3; it != end3; it++)
    //{
    //    *it = Vec3b(200, 200, 200);
    //}
    MatIterator_<Vec3b> begin3 = img3.begin<Vec3b>(), end3 = img3.end<Vec3b>();
    for (auto it = begin3; it != end3; it++)
    {
        *it = Vec3b(200, 200, 200);
    }
    imshow("三通道图像 灰白图:", img3);

    waitKey(0);

    destroyAllWindows();

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值