讀取16bit影象資料小結
阿新 • • 發佈:2018-12-18
opencv2 讀取16bit影象資料小結
https://blog.csdn.net/zhyh1435589631/article/details/49275945
今天師弟跑來問我一個關於opencv影象值讀取的問題, 原話是這樣的
在opencv中想要載入一幅16位的影象,滑鼠點選顯示其位置和灰度數值,但是我寫的程式中灰度數值最多隻能顯示255
拿到這個問題, 自己也不是很清楚, 因為自己其實也是剛剛才接觸opencv2.x, 雖然已經出來3了,anyway, 總是要裝下逼的, 於是就讓他把程式碼拿了過來, 打算自己除錯一下。
本來想試試qt除錯, 結果整了半天都沒停到斷點處, 只好換成了vs。
經過除錯發現:
- 一開始我們以為是資料載人有問題, 結果發現數據載入進來的確是 CV_16U型別的, 單通道灰度圖。 imread 的引數 CV_LOAD_IMAGE_UNCHANGED 和 CV_LOAD_IMAGE_ANYCOLOR | CV_LOAD_IMAGE_ANYDEPTH 效果是一致的
- 我們試圖用 Mat 的 at 方法讀取資料, 由於at 是個模板方法, 試了一下發現 uchar 不行, Vec2b 也不行(後來發現, Vec2b 使用在 2 通道的情況底下的), 顯然CV_16U 對應的型別應該是 2 個位元組, 故而用 ushort 型別, 正好滿足要求。
至此, 已經能夠滿足讀取灰度值的要求了。
auto it = img.at<ushort>(y, x);
- 1
3.師弟的程式中用了
uchar * data = img.data;
// img.at(i, j)
data = img.data + pt.y*img.step + pt.x*img.elemSize();
int intgray = (*data);
- 1
- 2
- 3
- 4
來獲取灰度值, 顯然是不正確的, 因為每個元素是 CV_16U 型別, ie, 每個影象資料佔 2 個位元組, 而這裡僅僅只是訪問到了該位置影象資料的第一個部分的資料, 前1個位元組, 還剩下一個位元組沒有讀取!!!
一般我們的intel cpu x86 x64 大多都是使用小端模式儲存的, ie, 低地址放低位元組, 高地址放高位元組。
在我們現在這個環境中, 高位元組部分沒有讀取, 因而需要加上高位元組部分, 同時需要注意 C++ 的 運算子優先順序, 優先順序′+′>′<<′′+′>′<<′
因而 data2 << 8 需要加上括號!!!
如下所示:
uchar * data = img.data;
// img.at(i, j)
data = img.data + pt.y*img.step + pt.x*img.elemSize();
uchar data2 = *(data + 1);
int intgray = (*data) + (data2 << 8);
- 1
- 2
- 3
- 4
- 5
4.注意opencv影象表示中是按照行列來表示的, 影象座標系處於影象的左上角, 而我們一般認為的 x, y 笛卡爾座標系的原點是位於 影象的左下角, 通過 at 方法讀取資料的時候, 要注意第一個引數應該表示影象的行, 第二個引數才是表示影象的列。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include<opencv.hpp>
#include <opencv\highgui.h>
using namespace cv;
using namespace std;
Mat img; //影象
const string lpwindowname = "影象09230021";
const string lpImageName = R"(E:\system dir\Desktop\QT\opencv2 computer vision\Opencv2\tmp\pixel\09230021.tif)";
void on_mousemove(int event, int x, int y, int flags, void* param);
int mid(int i, int a, int b);
int main()
{
img = imread(lpImageName, CV_LOAD_IMAGE_UNCHANGED);//載入影象
namedWindow(lpwindowname, 0);//建立視窗
imshow(lpwindowname, img);//在已經建立的視窗中顯示影象
setMouseCallback(lpwindowname, on_mousemove, 0);//響應滑鼠事件
waitKey(0);
destroyAllWindows();
return 0;
}
int mid(int i, int a, int b)
{
return min(max(i, min(a, b)), max(a, b));
}
void on_mousemove(int event, int x, int y, int flags, void* param)
{
//Font font;
//cvinitFont(&font, CV_FONT_HERSHEY_DUPLEX, 1, 1, 1, 1, CV_AA);
int width = img.cols;//圖片寬度
int height = img.rows;//圖片高度
Point text_pt;
Size text_size;
int baseline;
if (event == CV_EVENT_LBUTTONDOWN)
{
x = mid(x, 0, img.cols);
y = mid(y, 0, img.rows);
// auto tmp = img.type();
// auto tmp2 = img.depth();
Point pt = Point(x, y);
int aaa = img.channels();
uchar * data = img.data;
// img.at(i, j)
data = img.data + pt.y*img.step + pt.x*img.elemSize();
uchar data2 = *(data + 1);
int intgray = (*data) + (data2 << 8);
auto a2 = img.at<ushort>(y, x);
// ************* 後面就沒除錯了 ******************
char site[100];
sprintf(site, "(%d,%d)%d", pt.x, pt.y, intgray);
circle(img, pt, 2, Scalar(255, 255, 255), 1, CV_AA, 0);
text_size = getTextSize(site, CV_FONT_HERSHEY_DUPLEX, 1, 1, &baseline);
text_pt.x = mid(pt.x, 0, width - text_size.width);
text_pt.y = mid(pt.y, text_size.height + baseline, height);
putText(img, site, text_pt, CV_FONT_HERSHEY_DUPLEX, 1, Scalar(255,255,255), 1, CV_AA);
imshow(lpwindowname, img);
img = imread(lpImageName, CV_LOAD_IMAGE_UNCHANGED);//載入影象
}
}