目录 2、四大天王之Point_、Size_、Rect_、Scalar_ 上几篇文章,我们讲完了OpenCV中的常见基础结构。 从这篇博客开始,我们要踏上新的征程,我们要从像素的角度,来一起了解图像,一起了解OpenCV。今天这篇博客,我们讲最基本的图像像素操作,让我们一起,复习一下之前学的基本数据类型,然后一起走进今天的内容吧! 我想大家应该还记得我们之前学的数据类型,主要有如下: Mat类是我们学到的最基本的数据类型,从这节课开始往后的每节课,都会涉及到Mat类。Mat常用于声明或定义一个图像,偶尔也用于声明一个二维矩阵。 具体内容大家请看: 四大天王,这个名字也是很形象了,因为这个是除了Mat类之外最常用的四个类型,经常需要辅助Mat类做一些操作。他们分别是: 表示 点 的 Point_; 表示 尺寸 的 Size_; 表示 矩形 的 Rect_; 表示 颜色 的 Scalar_; 具体内容大家请看: 其他数据类型虽然不如上面四个常用,但是他们在自己的领域不可替代,会协助Mat类和上面四个常用类型做更多的事,实现更加丰富的功能: 表示 复数 的 Complex; 表示 三维点 的 Point_; 表示 旋转矩形 的 RotatedRect; 表示 序列 的 Range; 表示 角点 的 KeyPoint; 表示 索引与描述符距离 的 DMatch; 表示 迭代算法终止条件 的 TermCriteria; 具体内容大家请看: 首先我们先来了解一下像素 像素是计算机屏幕上所能显示的最小单位。用来表示图像的单位。每一个单位都会有其色彩数值。 我们经常能够见到的是黑白图像和彩色图像,其中黑白图像只有一个通道,彩色图像有三个通道,这些通道中每个像素点上的取值范围都是0-255; 对于黑白图像,0表示纯黑色,255表示纯白色,介于0-255之间的图像是灰色,根据数值的不同,灰色的程度也不同。我们也把这样的图像称之为灰度图像。 一个10×10的灰度图像排布如下: 对于彩色图像,有三个通道,每个通道各表示一种颜色,分别是BGR,也就是蓝绿红。以红色通道为例,如果取值为0,表示黑色,如果取值为255表示红色。我们之前学习Scalar_也学到了光学三原色,我们可以通过三种颜色构造出不同的颜色来。当三个通道的数值都为255时,图像为纯白色。 一个10×10的彩色图像排布如下: 操作像素之前,肯定要做的就是获取指向像素的指针,然后才能对像素进行操作。所以第一个就是要获取像素的指针。 但是我们看上面的图, 我么发现,对于灰度图和彩图,他们是不一样的,而且对于彩图来说,它是怎么存放的呢? 在计算机中,Mat是以序列的形式存放,对于灰度图,是这样的: 对于彩色图,我们要先知道,我们是一个像素一个像素排列,在像素内,是先B再G最后R。所以一幅彩色图像的表示如下: 然后再按照上面的灰度图那样进行排列。 所以根据上面的,我们可以知道: 对于灰度图: 一幅尺寸为 m×n (m行n列)的灰度图像,存储为长为 m×n 的序列; 想要访问第 i 行,第 j 列的像素,就是访问序列中的第 (i-1)×n+j 个像素,因为第1个像素序号是0,那这个像素的序号就是 (i-1)×n+j-1 。 对于彩色图: 一幅尺寸为 m×n (m行n列)的彩色图像,存储为长为 m×n×3 的序列; 想要访问第 i 行,第 j 列的元素就没有那么简单了: (1)首先上面就有 (i-1) 行像素,每行有 n×3 个元素,就是有 (i-1)×n×3 个元素。 (2)其次对于当前行,前面有 (j-1) 个像素,就是有 (j-1)×3 个元素。 (3)最后是对于当前位置的像素,我们知道顺序是BGR,所以B是0,G是1,R是2。 总的来说就是:访问第 i 行,第 j 列的像素,B是 (i-1)×n×3+(j-1)×3 ,G是 (i-1)×n×3+(j-1)×3+1 ,R是 (i-1)×n×3+(j-1)×3+2 。 对于彩色图像来说,如果真的按照上面讲的这样,就真的很麻烦了,所以在OpenCV里,对于彩色图像,我们提供了非常方便的获取像素指针的方式。 1.灰度图像 我们知道获取像素指针其实就是提供了一个访问像素的途径,在这里,我们用到一个at方法: 如果我们想获取坐标为(x,y)的像素,我们可以使用如下方法: 上面会返回一个uchar类型的数据,但是我们是需要一其数值,所以我们可以定义一个整型数据来获取,举个例子: 当然我们也可以使用我们之前学习Scalar类型来获取,因为是单通道,所以后三个位置全为0: 上面我们是先使用y,再使用x,这是因为我们是按照行列访问,如果我们是按照点访问,就需要用到我们之前学的点结构了: 示例如下: 输出代码及结果如下: 2.彩色图像 我们依然使用at方法但是这个时候,我们就不能直接使用int类型了,而且我们也要用到一个新的类型Vec3b: 跟上面一样使用at方法,但因为是三通道的,所以我们用到新的类型Vec3b,定义如下: 我们可以这样理解:这是一个包含三个uchar类型数据的一个结构。 然后我们想要获取三个通道的值,我们就依次获取其值就好: 我们获取到的值,它们是有范围的,我们在最开始也说了,对于灰度图来说,像素的取值范围是0-255,对于彩色图像来说,每个通道的取值范围也是0-255,那我们在操作像素的时候,一旦超过这个范围怎么办呢? 在OpenCV中,我们提供了一个方法来控制其取值范围: 这里有很多定义,其实这个定义的含义很简单: 大于255的值,变为255; 小于0的值,变为0; 其他的不改变; 这样我们就可以把范围控制在0-255之间。如果有学过激活函数的同学对这个形式就很清晰了,这个也可以算作图像像素的激活函数。 我们讲完了功能,我们做个实验,我们定义三个数据,然后使用这个定义控制其范围: 执行结果如下: 从今天这节内容开始,我们就要走进像素的世界了。也从今天开始,我们就要进入Mat的世界,带领Mat一起征战OpenCV的世界。 这个世界我们会遇到很多困难,但是不要担心,因为我们从未畏惧。 讲真,写这个很心累,教别人和自己学完全不是一个档次。学东西的时候,自己明白了就好,但是讲东西的时候,要给别人彻底讲明白。我不知道我的讲解水平如何,但是我的每一篇博客都是认真去写的,希望大家能够提出宝贵意见。我们一起加油!
一、前言
二、温故知新——基本数据类型
1、最基本之Mat类
2、四大天王之Point_、Size_、Rect_、Scalar_
3、各大分堂主
三、像素及相关概念
1、像素
2、灰度图与彩图
四、像素基本操作
1、获取像素指针
1.理论讲解
2.代码实战
src_gray.at<uchar>(y, x); //行在前,列在后,y表示行,x表示列
int sc1 = src_gray.at<uchar>(src_gray.rows/2, src_gray.cols/2);
Scalar sc2 = src_gray.at<uchar>(src_gray.rows / 2, src_gray.cols / 2);
src_gray.at<uchar>(Point(x, y));
Scalar sc3 = src_gray.at<uchar>(Point(src_gray.cols / 2, src_gray.rows / 2));
cout << "scalar of src_gray(Scalar) : " << sc1 << endl; cout << "scalar of src_gray(int) : " << sc2 << endl; cout << "scalar of src_gray(Point) : " << sc3 << endl;
Vec3b sc4 = src.at<Vec3b>(src.rows / 2, src_gray.cols / 2); int B = sc4.val[0]; int G = sc4.val[1]; int R = sc4.val[2]; Scalar sc5 = src.at<Vec3b>(Point(src.cols / 2, src_gray.rows / 2)); cout << "scalar of src(Vec3b) : [" << B << ", " << G << ", " << R << "] " << endl; cout << "scalar of src(Scalar) : " << sc5 << endl;
typedef Vec<uchar, 3> Vec3b;
int B = sc4.val[0]; int G = sc4.val[1]; int R = sc4.val[2];
2、控制像素范围
1.理论讲解
/////////////// saturate_cast (used in image & signal processing) /////////////////// /** @brief Template function for accurate conversion from one primitive type to another. The function saturate_cast resembles the standard C++ cast operations, such as static_cast<T>() and others. It perform an efficient and accurate conversion from one primitive type to another (see the introduction chapter). saturate in the name means that when the input value v is out of the range of the target type, the result is not formed just by taking low bits of the input, but instead the value is clipped. For example: @code uchar a = saturate_cast<uchar>(-100); // a = 0 (UCHAR_MIN) short b = saturate_cast<short>(33333.33333); // b = 32767 (SHRT_MAX) @endcode Such clipping is done when the target type is unsigned char , signed char , unsigned short or signed short . For 32-bit integers, no clipping is done. When the parameter is a floating-point value and the target type is an integer (8-, 16- or 32-bit), the floating-point value is first rounded to the nearest integer and then clipped if needed (when the target type is 8- or 16-bit). @param v Function parameter. @sa add, subtract, multiply, divide, Mat::convertTo */ template<typename _Tp> static inline _Tp saturate_cast(uchar v) { return _Tp(v); } /** @overload */ template<typename _Tp> static inline _Tp saturate_cast(schar v) { return _Tp(v); } /** @overload */ template<typename _Tp> static inline _Tp saturate_cast(ushort v) { return _Tp(v); } /** @overload */ template<typename _Tp> static inline _Tp saturate_cast(short v) { return _Tp(v); } /** @overload */ template<typename _Tp> static inline _Tp saturate_cast(unsigned v) { return _Tp(v); } /** @overload */ template<typename _Tp> static inline _Tp saturate_cast(int v) { return _Tp(v); } /** @overload */ template<typename _Tp> static inline _Tp saturate_cast(float v) { return _Tp(v); } /** @overload */ template<typename _Tp> static inline _Tp saturate_cast(double v) { return _Tp(v); } /** @overload */ template<typename _Tp> static inline _Tp saturate_cast(int64 v) { return _Tp(v); } /** @overload */ template<typename _Tp> static inline _Tp saturate_cast(uint64 v) { return _Tp(v); } template<> inline uchar saturate_cast<uchar>(schar v) { return (uchar)std::max((int)v, 0); } template<> inline uchar saturate_cast<uchar>(ushort v) { return (uchar)std::min((unsigned)v, (unsigned)UCHAR_MAX); } template<> inline uchar saturate_cast<uchar>(int v) { return (uchar)((unsigned)v <= UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0); } template<> inline uchar saturate_cast<uchar>(short v) { return saturate_cast<uchar>((int)v); } template<> inline uchar saturate_cast<uchar>(unsigned v) { return (uchar)std::min(v, (unsigned)UCHAR_MAX); } template<> inline uchar saturate_cast<uchar>(float v) { int iv = cvRound(v); return saturate_cast<uchar>(iv); } template<> inline uchar saturate_cast<uchar>(double v) { int iv = cvRound(v); return saturate_cast<uchar>(iv); } template<> inline uchar saturate_cast<uchar>(int64 v) { return (uchar)((uint64)v <= (uint64)UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0); } template<> inline uchar saturate_cast<uchar>(uint64 v) { return (uchar)std::min(v, (uint64)UCHAR_MAX); } template<> inline schar saturate_cast<schar>(uchar v) { return (schar)std::min((int)v, SCHAR_MAX); } template<> inline schar saturate_cast<schar>(ushort v) { return (schar)std::min((unsigned)v, (unsigned)SCHAR_MAX); } template<> inline schar saturate_cast<schar>(int v) { return (schar)((unsigned)(v-SCHAR_MIN) <= (unsigned)UCHAR_MAX ? v : v > 0 ? SCHAR_MAX : SCHAR_MIN); } template<> inline schar saturate_cast<schar>(short v) { return saturate_cast<schar>((int)v); } template<> inline schar saturate_cast<schar>(unsigned v) { return (schar)std::min(v, (unsigned)SCHAR_MAX); } template<> inline schar saturate_cast<schar>(float v) { int iv = cvRound(v); return saturate_cast<schar>(iv); } template<> inline schar saturate_cast<schar>(double v) { int iv = cvRound(v); return saturate_cast<schar>(iv); } template<> inline schar saturate_cast<schar>(int64 v) { return (schar)((uint64)((int64)v-SCHAR_MIN) <= (uint64)UCHAR_MAX ? v : v > 0 ? SCHAR_MAX : SCHAR_MIN); } template<> inline schar saturate_cast<schar>(uint64 v) { return (schar)std::min(v, (uint64)SCHAR_MAX); } template<> inline ushort saturate_cast<ushort>(schar v) { return (ushort)std::max((int)v, 0); } template<> inline ushort saturate_cast<ushort>(short v) { return (ushort)std::max((int)v, 0); } template<> inline ushort saturate_cast<ushort>(int v) { return (ushort)((unsigned)v <= (unsigned)USHRT_MAX ? v : v > 0 ? USHRT_MAX : 0); } template<> inline ushort saturate_cast<ushort>(unsigned v) { return (ushort)std::min(v, (unsigned)USHRT_MAX); } template<> inline ushort saturate_cast<ushort>(float v) { int iv = cvRound(v); return saturate_cast<ushort>(iv); } template<> inline ushort saturate_cast<ushort>(double v) { int iv = cvRound(v); return saturate_cast<ushort>(iv); } template<> inline ushort saturate_cast<ushort>(int64 v) { return (ushort)((uint64)v <= (uint64)USHRT_MAX ? v : v > 0 ? USHRT_MAX : 0); } template<> inline ushort saturate_cast<ushort>(uint64 v) { return (ushort)std::min(v, (uint64)USHRT_MAX); } template<> inline short saturate_cast<short>(ushort v) { return (short)std::min((int)v, SHRT_MAX); } template<> inline short saturate_cast<short>(int v) { return (short)((unsigned)(v - SHRT_MIN) <= (unsigned)USHRT_MAX ? v : v > 0 ? SHRT_MAX : SHRT_MIN); } template<> inline short saturate_cast<short>(unsigned v) { return (short)std::min(v, (unsigned)SHRT_MAX); } template<> inline short saturate_cast<short>(float v) { int iv = cvRound(v); return saturate_cast<short>(iv); } template<> inline short saturate_cast<short>(double v) { int iv = cvRound(v); return saturate_cast<short>(iv); } template<> inline short saturate_cast<short>(int64 v) { return (short)((uint64)((int64)v - SHRT_MIN) <= (uint64)USHRT_MAX ? v : v > 0 ? SHRT_MAX : SHRT_MIN); } template<> inline short saturate_cast<short>(uint64 v) { return (short)std::min(v, (uint64)SHRT_MAX); } template<> inline int saturate_cast<int>(unsigned v) { return (int)std::min(v, (unsigned)INT_MAX); } template<> inline int saturate_cast<int>(int64 v) { return (int)((uint64)(v - INT_MIN) <= (uint64)UINT_MAX ? v : v > 0 ? INT_MAX : INT_MIN); } template<> inline int saturate_cast<int>(uint64 v) { return (int)std::min(v, (uint64)INT_MAX); } template<> inline int saturate_cast<int>(float v) { return cvRound(v); } template<> inline int saturate_cast<int>(double v) { return cvRound(v); } template<> inline unsigned saturate_cast<unsigned>(schar v) { return (unsigned)std::max(v, (schar)0); } template<> inline unsigned saturate_cast<unsigned>(short v) { return (unsigned)std::max(v, (short)0); } template<> inline unsigned saturate_cast<unsigned>(int v) { return (unsigned)std::max(v, (int)0); } template<> inline unsigned saturate_cast<unsigned>(int64 v) { return (unsigned)((uint64)v <= (uint64)UINT_MAX ? v : v > 0 ? UINT_MAX : 0); } template<> inline unsigned saturate_cast<unsigned>(uint64 v) { return (unsigned)std::min(v, (uint64)UINT_MAX); } // we intentionally do not clip negative numbers, to make -1 become 0xffffffff etc. template<> inline unsigned saturate_cast<unsigned>(float v) { return static_cast<unsigned>(cvRound(v)); } template<> inline unsigned saturate_cast<unsigned>(double v) { return static_cast<unsigned>(cvRound(v)); } template<> inline uint64 saturate_cast<uint64>(schar v) { return (uint64)std::max(v, (schar)0); } template<> inline uint64 saturate_cast<uint64>(short v) { return (uint64)std::max(v, (short)0); } template<> inline uint64 saturate_cast<uint64>(int v) { return (uint64)std::max(v, (int)0); } template<> inline uint64 saturate_cast<uint64>(int64 v) { return (uint64)std::max(v, (int64)0); } template<> inline int64 saturate_cast<int64>(uint64 v) { return (int64)std::min(v, (uint64)LLONG_MAX); } /** @overload */ template<typename _Tp> static inline _Tp saturate_cast(float16_t v) { return saturate_cast<_Tp>((float)v); } // in theory, we could use a LUT for 8u/8s->16f conversion, // but with hardware support for FP32->FP16 conversion the current approach is preferable template<> inline float16_t saturate_cast<float16_t>(uchar v) { return float16_t((float)v); } template<> inline float16_t saturate_cast<float16_t>(schar v) { return float16_t((float)v); } template<> inline float16_t saturate_cast<float16_t>(ushort v) { return float16_t((float)v); } template<> inline float16_t saturate_cast<float16_t>(short v) { return float16_t((float)v); } template<> inline float16_t saturate_cast<float16_t>(unsigned v){ return float16_t((float)v); } template<> inline float16_t saturate_cast<float16_t>(int v) { return float16_t((float)v); } template<> inline float16_t saturate_cast<float16_t>(uint64 v) { return float16_t((float)v); } template<> inline float16_t saturate_cast<float16_t>(int64 v) { return float16_t((float)v); } template<> inline float16_t saturate_cast<float16_t>(float v) { return float16_t(v); } template<> inline float16_t saturate_cast<float16_t>(double v) { return float16_t((float)v); } //! @} } // cv
2.代码实战
int a = saturate_cast<uchar>(-100); //返回 0 cout <<"a = "<< a << endl; int b = saturate_cast<uchar>(100); //返回 100 cout << "b = " << b << endl; int c = saturate_cast<uchar>(1000); //返回 255 cout << "c = " << c << endl;
说在后面的话
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算