首页 > 编程知识 正文

opencv读取16位像,opencv提取像特征

时间:2023-05-05 18:43:05 阅读:268460 作者:260

索引目录 1. 图像在内存中的存储方式2. 像素访问2.1 使用下标M.at(i,j)2.2 指针ptr<>(row)访问图像像素2.3 使用迭代器iterator访问图像像素2.4 使用ptr<>(row, col)访问图像像素2.5 使用data结合step访问图像像素2.6 使用isContinouous()访问图像像素2.7 LTU查表法 3. 像素遍历4.图像像素的算术操作

1. 图像在内存中的存储方式

BGR而不是RGB,内存足够大,可以以连续的方式存储行,所以这些行创建单个长行,所有内容都在一个接一个的位置。我们可以使用cv :: Mat :: isContinuous()函数判断。

2. 像素访问

像素访问速度的快慢,排序如下:
【1】使用LUT查找表访问图像像素,LUT方法通过映射关系表大大减少相关操作的时间复杂度,是最快的处理方式,常用于(替换、反转、赋值、阈值、二值化、灰度变换等)图像操作。
【2】使用isContinuous()访问图像像素,图像必须是连续的才能使用
【3】使用ptr<>(row)访问图像像素,速度最快
【4】使用data结合step访问图像像素
【5】使用ptr<>(row, col)访问图像像素
【6】使用迭代器iterator访问图像像素,相比用指针直接访问像素可能出现越界问题,迭代器绝对是非常安全
【7】使用at<>()访问图像像素,速度是最慢的,直观

2.1 使用下标M.at(i,j) int width = img.cols;int height = img.rows;int dims = img.channels();//循环遍历像素读写for(int row = 0; row < width;++row){for(int col=0;col<height;++col ){if(dims==1)//黑白{img.at<uchar>(row, col) = saturate_cast<uchar>(img.at<uchar>(row, col) * 2);}if(dims==3)//彩图{img.at<Vec3b>(row, col)[0] = 255 - img.at<Vec3b>(row, col)[1];img.at<Vec3b>(row, col)[1] = 255 - img.at<Vec3b>(row, col)[2];img.at<Vec3b>(row, col)[2] = 255 - img.at<Vec3b>(row, col)[0];}}} 2.2 指针ptr<>(row)访问图像像素 for(int row=0;row<height;++row){uchar*current_row = img.ptr<uchar>(row);for(int col=0;col<width;++col){if (dims == 1){*current_row++ = 255 - *current_row;//current_row[]数组的首地址,每行第一个像素}if (dims == 3){*current_row++ = 255 - *current_row;*current_row++ = 255 - *current_row;*current_row++ = 255 - *current_row;}}}

参考博客:C/C++中 p++、++p、(*p)++、++*p的区别
或者

Mat outputImg= srcImg.clone(); int height = outputImg.rows; int weight= outputImg.cols; int colNum= outputImg.cols * outputImg.channels();//每一行元素个数 for (int row = 0; row < height ; ++row)//行循环 { uchar *srcData = srcImg.ptr<uchar>(row); uchar *outputData = outputImg.ptr<uchar>(row); for (int col = 0; col < colNum;j++)//列循环 { outputData[col] = saturate_cast<uchar>(255 - srcData[col]); } } 2.3 使用迭代器iterator访问图像像素 // 设置参数 dstImg = srcImg.clone(); // 设置目标图像与源图像一样 // 获取迭代器 Mat_<Vec3b>::iterator it = dstImg.begin<Vec3b>(); // 初始位置的迭代器 Mat_<Vec3b>::iterator itEnd = dstImg.end<Vec3b>(); // 终止位置的迭代器 // 存取彩色图像像素 for (; it != itEnd; it++) // 行循环 { // 开始处理每个像素,在OpenCV中,存储顺序是BGR (*it)[0] = (*it)[0] / div * div + div / 2;//blue通道 (*it)[1] = (*it)[1] / div * div + div / 2;//绿色通道 (*it)[2] = (*it)[2] / div * div + div / 2;//蓝色通道 } 2.4 使用ptr<>(row, col)访问图像像素 dstImg = srcImg.clone(); // 设置目标图像与源图像一样for (int row = 0; row < srcImg.rows; row++){for (int col = 0; col < srcImg.cols; col++){Vec3b* pData = srcImg.ptr<Vec3b>(row, col);//彩图(*pData)[0] = 255 - (*pData)[0];(*pData)[1] = 255 - (*pData)[1];(*pData)[2] = 255 - (*pData)[2]; //这种方式也可以//uchar* pData = m2.ptr<uchar>(row, col);//*(pData + 0) = 255 - *(pData + 0);//*(pData + 1) = 255 - *(pData + 1);//*(pData + 2) = 255 - *(pData + 2);}} 2.5 使用data结合step访问图像像素

成员函数step是返回该Mat对象一行所占的数据字节数。
成员函数data:uchar类型的指针,指向Mat数据矩阵的首地址
参考博客:https://blog.csdn.net/CxC2333/article/details/107735638

dstImg = srcImg.clone(); // 设置目标图像与源图像一样 uchar* pData = srcImg.data;MatStep mst = srcImg.step;for (int row = 0; row < srcImg.rows; row++){for (int col = 0; col < srcImg.cols; col++){*(pData + row * mst + col * srcImg.channels() + 0) = 255 - *(pData + row * mst + col * srcImg.channels() + 0);*(pData + row * mst + col * srcImg.channels() + 1) = 255 - *(pData + row * mst + col * srcImg.channels() + 1);*(pData + row * mst + col * srcImg.channels() + 2) = 255 - *(pData + row * mst + col * srcImg.channels() + 2);}} 2.6 使用isContinouous()访问图像像素

图像行与行之间的存储可能是不连续的,进行像素值遍历,很大程度上造成数据指针移动的浪费。一般经过裁剪的Mat图像,都不再连续了,如cv::Mat crop_img = src(rect);crop_img 是不连续的Mat图像,如果想转为连续的,最简单的方法,就是将不连续的crop_img 重新clone()一份给新的Mat就是连续的了

int row = src.rows; int col = src.cols; cv::Mat dstImg = src.clone(); // 判断是否是连续图像,即是否有像素填充 if (src.isContinuous() && dstImg.isContinuous()) { row = 1; // 按照行展开 col = col * src.rows * src.channels(); } // 遍历图像的每个像素 for (int i = 0; i < row; i++) { // 设定图像数据源指针及输出图像数据指针 const uchar* pSrcData = src.ptr<uchar>(i); uchar* pResultData = temp.ptr<uchar>(i); for (int j = 0; j < col; j++) { *pResultData++ = 255 - *pSrcData++; } } 2.7 LTU查表法 int row = src.rows; int col = src.cols; Mat temp = src.clone(); // 建立LUT 反色table uchar LutTable[256 * 3]; for (int i = 0; i < 256; ++i) { LutTable[i * 3] = 255 - i; LutTable[i * 3+1] = 255 - i; LutTable[i * 3+2] = 255 - i; } Mat lookUpTable(1, 256, CV_8UC3, LutTable); // 应用索引表进行查找 LUT(src, lookUpTable, temp);

参考博客:【OpenCV】之LUT函数

3. 像素遍历

OpenCV3 之 遍历图像像素的14种方法

4.图像像素的算术操作

在原图上src1操作,如果src2和src1逻辑操作为1,src1像素值不变,否则src1像素值为0

// 逻辑操作 Mat dst1, dst2, dst3;bitwise_and(src1, src2, dst1);bitwise_xor(src1, src2, dst2);bitwise_or(src1, src2, dst3); // 取反操作Mat dst;bitwise_not(src, dst);Mat dst=~src;

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。