今天学习所谓的高效连续遍历图像,搞笑了一下 哈哈 按照课本的程序敲代码,我发现并没有高效啊?基本没有什么变化啊?问题我写在程序的注释里面了,希望前辈可以给出指点。
#include <opencv.hpp>
#include <iostream>
#include <windows.h>
using namespace cv;
using namespace std;
/*C::Mat的一个成员函数 isContinuous 是否进行填补 如果没有进行填补 可以将图像看成一个一维数组
我们也可以使用reshape这个方法来重置矩阵的维度;
if(image.isContinuous())
{
image.reshape(1,image.rows * image.cols) //其中 参数1 代表通道数 参数二代表行数
}
int nl = image.rows;
int nc = image.cols * image.channels();
reshape 不需要内存拷贝或者重新分配就能改变矩阵的维度,两个参数分别为新的通道数和新的hangshu
*/
void colorReduce(Mat & image, int div )
{
int nl = image.rows;
int nc = image.cols * image.channels();
if (image.isContinuous())
{
nc = nc * nl;
nl = 1;
}
for (int j = 0; j < nl; j++)
{
/*uchar * data = image.ptr<uchar>(j); 是为了获取j行的指针,
在cv::Mat中,图像数据以unsigned char 的形式保存在一块内存当中。这块内存的首地址可以通过mat的成员变量data找到 data是一个unsigned char类型的指针 所以循环可以这样开始: uchar * data = image.data
这个指针还有一个用处 就是可以检测是否成功读取了一张图片 如果顺利读取了 指针的值不为0 (NULL) 否则指针的值为NULL 这样就可以用if语句来判断是否成功读取了图片 从当前行到下一行可以采取 :data+ = image.step*/
uchar * data = image.ptr<uchar>(j);
for (int i = 0; i < nc; i++)
{
data[i] = data[i] / div *div + div / 2;
}
}
}
int main()
{
Mat image;
image = imread("C:\\Users\\Administrator\\Pictures\\Test1.jpg",IMREAD_GRAYSCALE);
/*一个非常奇怪的问题,也不知道咋回事 我改变图片的通道,就是换成灰色图像 时间也是 16就没有变过
这是咋回事呢 遍历的像素点少了 时间不应该短吗*/
DWORD Start_time = GetTickCount();
colorReduce(image,64);
DWORD End_time = GetTickCount();
cout << "执行时间:" << End_time - Start_time << endl;
namedWindow("高效遍历");
imshow("高效遍历", image);
waitKey(0);
return 0;
}
#include<opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main()
{
Mat image;
image = imread("C:\\Users\\Administrator\\Pictures\\Test2.jpg", IMREAD_UNCHANGED);
int nl = image.rows;
int nc = image.cols;
int k = 0;
k = image.elemSize();
cout << "行宽:" << k << endl;
cout << nl << '\t' << nc << endl;
cout << "地址测试" << endl;
//一开始按照课本上写的 image.at(1,1) 死活编译不成功,后来加上了类型声明就对了 <uchar> 输出乱码
//再后来 百度 加上了强制类型转换。
cout << int(image.at<uchar>(0, 4) )<< endl;
/*按照测试的结果来看,一个768&1366的图片 一共有768行 1366列 其中每行包括1366个像素 每个像素由RGB三个分量合并而成
所以一行应该有 1366 * 3个 usigned char 类型的数据。经测试 准确无误 ,不巧的是测试过程中发现 执行串口 显示不了这么多的数据
窗口的属性中 默认显示 300行 每行80个 这样多余的就被覆盖了,自己修改一下窗体的属性即可。
*/
for (int j = 0; j < 1; j++)
{
for (int i = 0; i < nc*image.channels(); i++)
{
cout << int(image.at<uchar>(j, i)) <<
'\t' ;
k++;
}
cout <<"一行有" << endl;
cout << k;
}
return 0;
}
/* image.at<uchar>(i, j) 这样代表 这个坐标位置下的像素 ,对于灰色图像只有一个
对于彩色图像 举个例子吧 768 *1366 这个 i 依旧表示第几行 j的取值范围是0-1366 *3 -1
那么此时上述语句就代表 是一个像素点的某一分量。
&image.at<uchar>(i, j)就是得到这个数据的地址 ,通常我们使用这个方法,但是书本上还介绍了另一种 这里了解一下吧;
data = image.data + i*image,step +j*image.elemSzie
解释一下 image.data 代表图像第一个元素的指针地址 i代表行数 step代表图像的行宽 奶奶的 行宽什么意思呢 意思就是一行有多少个数据
比如彩色图形 766 *1366 一行就是有 1366 * 3 数据 行宽就是4098
elemSize代表了 一个像素点由几个分量组成 比如彩色就是三个,这样解释应该比较明白了。
*/