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

时间:2022-06-23 09:46:35

在用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://*.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://*.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()需要区别如下:

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

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;
}

结果图如下:

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

还有留下的问题需要解决,继续看opencv,就是如果我要逐个操作每个像素值,我是否应该将CV_8UC1类型转为浮点型计算完成之后再转回来。还有另外一个问题就是负数的二进制表示还需要再看看资料。

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

  1. 从Excel中导入数据时,提示&OpenCurlyDoubleQuote;未在本地计算机上注册&OpenCurlyDoubleQuote;Microsoft&period;ACE&period;OLEDB&period;12&period;0”提供程序”的解决办法

    注意,64位系统,用64位的补丁文件; https://www.cnblogs.com/A2008A/articles/2438962.html 操作系统:使用的是64位的Windows Server ...

  2. 读取redis中的数据时出现:MISCONF Redis is configured to save RDB snapshots

    读取redis中的数据时出现:MISCONF Redis is configured to save RDB snapshots   以下为异常详细信息: Exception in thread &q ...

  3. 触发器修改后保存之前的数据 表中插入数据时ID自动增长

    create or replace trigger t before update on test5 for each rowbegin insert into test55 values (:old ...

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

    在Oracle中更新数据时,抛出了一个 :ORA-01008 not all variables bound, 我的理解是不是所有的变量/参数都有边界,不懂: 后来知道了,原来是“不是所有变量/参数都 ...

  5. OpenCV几种访问cv&colon;&colon;Mat数据的方法

    一般来说,如果是遍历数据的话用指针ptr比用at要快.特别是在debug版本下.因为debug中,OpenCV会对at中的坐标检查是否有溢出,这是非常耗时的. 代码如下 #include <op ...

  6. [MySQL]load data local infile向MySQL数据库中导入数据时,无法导入和字段不分离问题。

    利用load data将文件中的数据导入数据库表中的时候,遇到了两个问题. 首先是load data命令无法执行的问题: 命令行下输入load data local infile "path ...

  7. C&num;读取Excel表中的数据时,为何有些行的字段内容读取不到

    转载:http://bbs.csdn.net/topics/360220285 1.当某列数据中含有混合类型时,在.NET中使用Microsoft.Jet.OLEDB.4.0来读取Excel文件造成数 ...

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

    //若从excel中读取的时间值为空值时,做如下转换 string YDKGSJ = string.Empty; if (dbdata.Rows[i]["约定开工时间"].ToSt ...

  9. 在向&quot&semi;带有自增字段的数据库表&quot&semi;中插入数据时&comma;自定义&quot&semi;该自增字段&quot&semi;的数据

    在设计数据库表的时候,经常会使用自增主键或其他自增字段.比如: DB_UserGroups表中GroupID为该表主键,并为自增字段. 但在将某字段设置自增后,想在插入数据时,人为指定自增字段的数据内 ...

随机推荐

  1. VisualSVN Server搭建VDFS分布式仓研究(未成功)

    FSFS与VDFS的使用区别在于FSFS是本地仓库,VDFS是分布式仓库,实现在同一个局域网内多台仓库进行同步:以下是我的猜测,因为没搭建成功: 1.必须是同一个局域网,如果有外内网基本是不可实现,需 ...

  2. QT点击&quot&semi;X&quot&semi;按钮,调用closeEvent&lpar;&rpar;函数来实现调用特定事件(附:粗略介绍QT的信号与槽的使用方法)

    背景: QT在用户关闭窗口(直接点击"X"键)时,程序一般都需要做一些善后的事情,就我现在的程序来说,既关闭USB.如何实现? 正文: 首先,在对应窗体的".h&quot ...

  3. MappingJacksonHttpMessageConverter过期

    最新在做一个SSM整合学习项目,maven加上jackson库,spring配置json,tomcat不能正常部署启动 Maven配置 <!-- 引入jackson,防止ajax调用返回json ...

  4. 关于rand&lpar;&rpar;与srand&lpar;&rpar;函数

    rand函数功能为获取一个伪随机数(伪随机数的概念下面会有介绍). 一.函数名: rand(); 二.声明: int rand(); 三.所在头文件: stdlib.h 四.功能: 返回一个伪随机数. ...

  5. MyBatis-plus 代码自动生成器

    MyBatis-plus  代码自动生成器 1.添加pom文件依赖 <!-- Mybatis-Plus 自动生成实体类--> <dependency> <groupId& ...

  6. &lbrack;LOJ 6270&rsqb;数据结构板子题

    Description 有n个区间,第i个区间是[li,ri],它的长度是ri−li. 有q个询问,每个询问给定L,R,K,询问被[L,R]包含的且长度不小于K的区间数量. 你想,像这种板子题,你随手 ...

  7. Aliyun上Linux服务器挂载数据盘及速度测试

    原始文档来自于阿里云官方文档:  Linux 系统挂载数据盘 铁锚 于 2013年12月19日 根据自己的需要进行整理 操作系统: CentOS 6.3, 平台  : 阿里云 ECS 云服务器 1. ...

  8. (二)JavaScript 输出

    avaScript 没有任何打印或者输出的函数. JavaScript 显示数据 JavaScript 可以通过不同的方式来输出数据: 使用 window.alert() 弹出警告框. 使用 docu ...

  9. Redis Pubsub命令用法

    一.什么是pub/sub及实现Pub/Sub功能(means Publish, Subscribe)即发布及订阅功能. Redis通过publish和subscribe命令实现订阅和发布的功能. 订阅 ...

  10. java&period;io&period;File中字段的使用

    File.pathSeparator指的是分隔连续多个路径字符串的分隔符,例如:Java   -cp   test.jar;abc.jar   HelloWorld就是指“;” File.separa ...