访问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,结果得出:

负数在计算机内部是用补码表示的

例如 -1

1 的原码是 0000 0001

则 -1 的反码是 1111 1110

补码是 1111 1111

因为我强制转换为int指针,所以一次取得32为,结果就会发现取出来的是int(‘\xff\xff\xff\xff‘);所以将这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类型转为浮点型计算完成之后再转回来。还有另外一个问题就是负数的二进制表示还需要再看看资料。

时间: 2024-10-20 07:59:03

访问cv::Mat中的数据时遇到的指针类型问题的相关文章

OpenCV访问Mat对象中数据时发生异常---Mat中的数据访问

7.1和7.1.1由于越狱不成熟,半完美越狱后电脑上无法访问系统越狱目录,如var usr 等等. 今天有些意外地发现,可以在电脑上使用手机的越狱目录我手机 i4 7.1.1 联通 半完美越狱,没装Afc2Add,也没装Appsync 附上  --->我的半完美越狱过程 好了,下面直接正题 一.前提,必须安装ifile! 打开ifile,并转到 /var/mobile/media 目录下,然后点击右上角的 [ 编辑 ]如图: 二.点左下角的 + 号创建,如图: 三.点 [ 类型],选择[符号链接

android 修改listview中adapter数据时抛出异常java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification问题

近日在做项目时遇到非必现crush,具体异常信息为: // Short Msg: java.lang.IllegalStateException // Long Msg: java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not mo

在Oracle中更新数据时,抛出:ORA-01008: not all variables bound

在Oracle中更新数据时,抛出了一个 :ORA-01008 not all variables bound, 我的理解是不是所有的变量/参数都有边界,不懂: 后来知道了,原来是“不是所有变量/参数都确定”, 就是有些变量没有指定,缺少变量参数, 最后发现是因为在写三层时少写了一个"new OracleParameter(":ID",userinfo.ID);" 导致的.

OpenCV几种访问cv::Mat数据的方法

一般来说,如果是遍历数据的话用指针ptr比用at要快.特别是在debug版本下.因为debug中,OpenCV会对at中的坐标检查是否有溢出,这是非常耗时的. 代码如下 #include <opencv2\core\core.hpp> #include <opencv2\highgui\highgui.hpp> #include <iostream> int main() { char *srcName="e://vedio//001.jpg"; c

在报表中录入数据时如何实现行列转换

应用场景及需求: 某电力集团在实际应用中需要在填报数据时将数据库中的字段以更符合业务人员使用习惯的方式进行呈现,其中就有行列转换的情况.在常规的应用开发中,一般都是通过专门设计的数据界面进行录入,然后再通过程序转换存入数据库.而现在有了集算器支持的润乾填报表,就能够处理各种有关数据结构的填报需求了,这种行列转换自然也不在话下. 首先,我们来看一下行列转换的准确含义: 在一些企业应用中,一些指标项在数据库存储时会做为不同的字段存储,这样数据结构会更加清晰,但是在报表展示或填报表数据录入时,又需要将

在往oracle中插数据时,如何处理excel读取的时间空值

//若从excel中读取的时间值为空值时,做如下转换 string YDKGSJ = string.Empty; if (dbdata.Rows[i]["约定开工时间"].ToString() == "") { YDKGSJ = "null,"; } else { YDKGSJ = "to_date('" + Convert.ToDateTime(dbdata.Rows[i]["约定开工时间"]) + &q

【转】从QDataStream向QByteArray中写入数据时的注意点(QT)

最近发现从QDataStream向QByteArray中写入数据常常是写不进去的,通过查看QT的源码: QDataStream &operator>>(QDataStream &in, QByteArray &ba){ ba.clear(); quint32 len; in >> len; if (len == 0xffffffff) return in; const quint32 Step = 1024 * 1024; quint32 allocated

向数据库中插入数据时字符集或查询是数据无法正常显示出现乱码问题

当向数据库插入数据出错或出局无法正常显示出现乱码时.首先应该想到的是数据库的编码问题.查看当前数据库服务器默认对数据库处理的字符集 show variables like  'character_set%'; character_set_client: 默认客户端来的数据格式 character_set_connection : 连接层字符集 character_set_database:  当前数据库字符集 character_set_results:服务器给外部的字符集 假如客户端字符集与数

JBOSS EAP6 系列二 客户端访问位于EAR中的EJB时,jndi name要遵守的规则

EJB 的 jndi语法(在整个调用远程ejb的过程中语法的遵循是相当重要的) 参见jboss-as-quickstarts-7.1.1.CR2\ejb-remote\client\src\main\java\org\jboss\as\quickstarts\ejb\remote\client\RemoteEJBClient.java 中的注释: <span style="font-size:18px;"><span style="font-size:18p