訪問cv::Mat中的數據時遇到的指針類型問題


在用Opencv的時候由於下圖原本的圖像尺寸是1111*1111,要進行resize,代碼如下:

cv::Mat img = cv::imread("//Users//apple//td3//vase//19201.png",CV_LOAD_IMAGE_GRAYSCALE);
cv::Mat img2;
cv::resize(img, img2, cv::Size(400,400),0,0, cv::INTER_AREA);

因為我根本不知道img的數據是什么類型(不知道數據類型根本無法通過指針計算來訪問每個像素的值,而且我想操作逐個像素來做blur),然后我就用int指針去訪問,結果自然是很容易錯誤的。我將訪問的值寫入文本之后發現都是些奇怪的數值,例如-1,4294967296(2^32),還以其他奇葩數值。結果如果我利用其opencv自己重載的函數輸出:

std::cout << img2.at<int>(0,0); //輸出(0,0)的像素值為-1
std::cout << img2; //輸出矩陣的所有像素的像素值,結果很正常屬於[0,255]

結果我以為矛盾,然后直接訪問img2.data成員,寫了一些很沒道理的代碼:

for(int row = 0; row <img2.rows; row++){
    uchar *ptr = (img2.data + row*img2.step);
    for(int col = 0; col < img2.cols; col++){
        int *intTmp = (int*)(ptr+col); //結果輸出自然是錯的,因為img2的數據類型是uchar,一個像素用8位表示
        std::cout << *intTmp << ' ';   //而強制轉換成int*后訪問的時候就直接取出32位
    }
    std::cout << std::endl;
}

然后設置斷點查看了下img2.data里面的數據是'\xff',然后用cout打印出來是'\377',原來是字符串的十六進制和八進制表示,仔細分析為什么'\377'的值是-1,結果得出:

在C中有兩種特殊的字符,八進制轉義字符和十六進制轉義字符,八進制字符的一般形式是'\ddd',d是0-9的數字。十六進制字符的一般形式是'\xhh',h是0-9或A-F內的一個。八進制字符和十六進制字符表示的是字符的ASCII碼對應的數值。比如

'\063'表示的是字符'3',因為'3'的ASCII碼是30(十六進制),48(十進制),63(八進制)。

'\x41'表示的是字符'A',因為'A'的ASCII碼是41(十六進制),65(十進制),101(八進制)。

負數在計算機內部是用補碼表示的

例如 -1

1 的原碼是 0000 0001

則 -1 的反碼是 1111 1110

補碼是 1111 1111

因為我強制轉換為int指針,所以是指針指向的數是有符號的,並且一次性取得32位,將這4個'\xff'表示為二進制:1111 1111 1111 1111 1111 1111 1111 1111(32個1)所以在有符號整數中的值就是-1,而在無符號中的值又是4294967295。但是均不是我想要的255,然后查了各種資料,結果看到這個網站:

http://stackoverflow.com/questions/23819445/why-is-xff-not-being-recognized

中有一句話剪切過來:

'\xff' is a character constant, not a string literal. String literals have no signedness; they represent arrays. Type char may be either signed or unsigned, depending on the implementation. If plain char is unsigned, then '\xff' has the value 255 of type int. If plain char is signed, the wording of the standard is unclear (at least to me). 

 結果我試了幾組代碼:

char *sign_t = new char('\377');
int j = *sign_t; //值是-1

uint *intTest = new uint('\xff\xff\xff\xff'); //值是4294967295

uchar *t = new uchar('\xff');
int *pp = (int*)t; //值是255

結果我明白了很多,錯誤始終是在一開始我根本不清楚cv::Mat中的數據的深度和通道信息,然后我搜索了到了一個解答:

http://stackoverflow.com/questions/10167534/how-to-find-out-what-type-of-a-mat-object-is-with-mattype-in-opencv

http://answers.opencv.org/question/742/matrix-depth-equals-0/

將其解答剪切出來,我們可以用img2::type(), img2::channels(), img2::depth()來確定mat的類型。但是img2::type與img2::depth()需要區別如下:

So,至此所有問題都明朗了,最后貼上一個正確訪問CV_8UC1類型Mat.data數據的代碼:

for(int row = 40; row <img2.rows-200; row++){
    uchar *ptr = (img2.data + row*img2.step);
    for(int col = 20; col < img2.cols-200; col++){
        uchar *ptrTmp = ptr+col;
        *ptrTmp = 0;
    }
    std::cout << std::endl;
}

 

結果圖如下:

 

 

 

 

 

 

 

還有留下的問題需要解決,繼續看opencv,就是如果我要逐個操作每個像素值,我是否應該將CV_8UC1類型轉為浮點型計算完成之后再轉回來。還有另外一個問題就是負數的二進制表示還需要再看看資料。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM