这两天编程实现同态滤波,可实现的结果却令我大跌眼镜,滤波后的图像严重发生了错位,简直分辨不出图像的内容,检查程序没有发现错误,这让我一直很郁闷。今天早上在百度上搜到一个帖子,帖子是别人转的,但原帖子的作者也遇到过这样的错误。作者说宽度为偶数的图片不会发生这样的情况,但宽度为奇数的图片就会发生上面的错误。我也拿了几张图片试验了一下,正如作者所说。究其原因,原来是IplImage的widthstep在作怪,当width为偶数时,widthstep与width*nchannels相等,但当width为奇数时,就会填充一个单位像素的长度使widthstep成为偶数。看了帖子,我也找到了出错的原因,我就马上修改程序。呵呵,结果正常显示了。只要把读取数据的i*width+j改为i*widthstep+j就可以了。

width是图像宽度,可为任意值;widthstep是行字节数,应该是4的倍数,不一定等于width,nchannels为图像通道数。 #define WIDTHBYTES(bits) (((bits)+31)/32*4) 看看这个公式你就明白了。

对ROI和widthStep的补充

ROI和widthStep在实际工作中有很重要的作用,在很多情况下,使用它们会提高计算机视觉代码的执行速度。这是因为它们允许对图像的某一小部分进行操作,而不是对整个图像进行运算。在OpenCV中,普遍支持ROI和widthStep,函数的操作被限于感兴趣区域。要设置或取消ROI,就要使用cvSetImageROI()和cvResetImageROI()函数。如果想设置ROI,可以使用函数cvSetImageROI(),并为其传递一个图像指针和矩形。而取消ROI,只需要为函数cvResetImageROI()传递一个图像指针。

  1. void cvSetImageROI( IplImage* image, CvRect rect );
  2. void cvResetImageROI( IplImage* image );

为了解释ROI的用法,我们假设要加载一幅图像并修改一些区域,如例3-12的代码,读取了一幅图像,并设置了想要的ROI的x,y,width和height的值,最后将ROI区域中像素都加上一个整数。本例程中通过内联的cvRect()构造函数设置ROI。通过cvResetImageROI()函数释放ROI是非常重要的,否则,将忠实地只显示ROI区域。

例3-12:用imageROI来增加某范围的像素

  1. // roi_add <image> <x> <y> <width> <height> <add>
  2. #include <cv.h>
  3. #include <highgui.h>
  4. int main(int argc, char** argv)
  5. {
  6. IplImage* src;
  7. if( argc == 7 && ((src=cvLoadImage(argv[1],1)) != 0 ))
  8. {
  9. int x = atoi(argv[2]);
  10. int y = atoi(argv[3]);
  11. int width = atoi(argv[4]);
  12. int height = atoi(argv[5]);
  13. int add = atoi(argv[6]);
  14. cvSetImage ROI(src, cvRect(x,y,width,height));
  15. cvAddS(src, cvScalar(add),src);
  16. cvResetImageROI(src);
  17. cvNamedWindow( "Roi_Add", 1 );
  18. cvShowImage( "Roi_Add", src );
  19. cvWaitKey();
  20. }
  21. return 0;
  22. }

使用例3-12中的代码把ROI集中于一张猫的脸部,并将其蓝色通道增加150后的效果如图3-3所示。【45~46】

(点击查看大图)图3-3:在猫脸上用ROI增加150像素的效果

通过巧妙地使用widthStep,我们可以达到同样的效果。要做到这一点,我们创建另一个图像头,让它的width和height的值等于interest_rect的width和height的值。我们还需要按interest_rect起点设置图像起点(左上角或者左下角)。下一步,我们设置子图像的widthStep与较大的interest_img相同。这样,即可在子图像中逐行地步进到大图像里子区域中下一行开始处的合适位置。最后设置子图像的imageDate指针指向兴趣子区域的开始,如例3-13所示。

例3-13:利用其他widthStep方法把interest_img的所有像素值增加1

  1. // Assuming IplImage *interest_img; and
  2. //   CvRect interest_rect;
  3. //   Use widthStep to get a region of interest
  4. //
  5. // (Alternate method)
  6. //
  7. IplImage *sub_img = cvCreateImageHeader(
  8. cvSize(
  9. interest_rect.width,
  10. interest_rect.height
  11. ),
  12. interest_img->depth,
  13. interest_img->nChannels
  14. );
  15. sub_img->origin = interest_img->origin;
  16. sub_img->widthStep = interest_img->widthStep;
  17. sub_img->imageData = interest_img->imageData +
  18. interest_rect.y * interest_img->widthStep    +
  19. interest_rect.x * interest_img->nChannels;
  20. cvAddS( sub_img, cvScalar(1), sub_img );
  21. cvReleaseImageHeader(&sub_img);

看起来设置和重置ROI更方便一些,为什么还要使用widthStep?原因在于有些时候在处理的过程中,想在操作过程中设置和保持一幅图像的多个子区域处于活动状态,但是ROI只能串行处理并且必须不断地设置和重置。

最后,我们要在此提到一个词-- 掩码或模板,在代码示例中cvAddS()函数允许第四个参数默认值为空:const CvArr* mask=NULL。这是一个8位单通道数组,它允许把操作限制到任意形状的非0像素的掩码区,如果ROI随着掩码或模板变化,进程将会被限制在ROI和掩码的交集区域。掩码或模板只能在指定了其图像的函数中使用。

转载于:https://www.cnblogs.com/hualimengyu/p/3454162.html

关于IplImage的widthstep相关推荐

  1. OpenCV里IplImage的widthStep参数 和width参数

    一直以为IplImage结构体中的widthStep元素大小等于width*nChannels,大错特错!(为了快速访问,要内存对齐啊)查看OpenCV2.1的源码,在src/cxcore/cxarr ...

  2. 【OpenCV】IplImage和char *的相互转换,以及极易忽视的细节

    OpenCV中IplImage和单字节char*的相互转换 从 IplImage到 char* : data = image->imageData //对齐的图像数据或者data = image ...

  3. OpenCV图像、矩阵、数组介绍

    一.结构 IplImage |-- int nChannels; // Number of color channels (1,2,3,4) |-- int depth; // Pixel depth ...

  4. OpenCV里IplImage数据结构中的width和widthStep

    转自http://nst1987.blog.163.com/blog/static/14950891120101120114029646/ IplImage有两个属性容易导致错误:width和widt ...

  5. 谈谈我对opencv中IplImage图像参数widthstep的理解

    最近在弄vs与MATLAB混合编程实现图像识别的东西,刚接触到opencv还生疏的很,遇到了各种各样奇葩的问题,其中不管怎样释放内存都不会少的内存泄露实在是让我很头疼,现在开始一点点的弄每个图像的参数 ...

  6. OpenCV中IplImage和单字节char*的相互转换

    已知 IplImage* image 和 char* data 从 IplImage 到 char* : data = image->imageData //对齐的图像数据 或者 data =  ...

  7. IplImage简介

    IplImage简介 结构定义: typedef struct _IplImage {int nSize; /* sizeof(IplImage) */int ID; /* version (=0)* ...

  8. 【转】OpenCV里IplImage数据结构极易出错的问题,IplImage和单字节char*的相互转换

    http://blog.csdn.net/liuyi1985/article/details/2174328 http://blog.csdn.net/liuyi1985/article/detail ...

  9. IplImage类型解释和举例

    1.IplImage结构 typedef struct _IplImage {int nSize; /* sizeof(IplImage) */int ID; /* version (=0)*/int ...

  10. OpenCV中IplImage/CvMat/Mat转化关系

    原文链接:http://www.cnblogs.com/summerRQ/articles/2406109.html 如对内容和版权有何疑问,请拜访原作者或者通知本人. opencv中常见的与图像操作 ...

最新文章

  1. [经验]无线鼠标和无线键盘真的不能用了?——雷柏的重生之路~
  2. python version 2.7 required,which was not found
  3. php reader oleread,PHP 实用技巧集锦
  4. HCIE培训后的面试小诀窍
  5. MFC之ComboBox控件用法
  6. tensorflow2 目标检测_一文了解YOLO-v4目标检测
  7. 从前端到后端的跨域攻击与防御
  8. Sqoop导入到hdfs
  9. 配置visual studio code进行asp.net core rc2的开发(转载jeffreywu)
  10. 老农的计算机学习笔记(二)硬件篇
  11. 数据防泄密工作企业该如何开展
  12. Redis过期策略---实现原理
  13. Linux配置及指令
  14. RFID 中间件规范 -- ALE 介绍
  15. ICIAR2018数据集下载
  16. Java 环境下使用 AES 加密的特殊问题处理
  17. 录像加文档,双管齐下!腾讯内部大热的Java知识宝典
  18. C语言输出教学日历表
  19. UC伯克利马毅教授于2021年2月23日发的微博
  20. 国产化适配之人大金仓数据库(二)数据迁移

热门文章

  1. 使用git可视化工具上传你修改的代码
  2. 2021年2 分以上优秀护理相关SCI 期刊汇总
  3. clover写入efi_Clover EFI bootloader for Mac(四叶草启动引导工具)
  4. CentOS8安装MySQL可视化客户端
  5. c语言 16进制编辑器,十六进制编辑器(010 Editor)
  6. 6. HBase优化
  7. python制作录屏软件_自制录屏软件,不到30行代码(仅供学习研究)
  8. windows安装和使用git工具
  9. mysql字符串替换_MySQL的字符串替换更新操作
  10. 注意!JWT不是万能的,入坑需谨慎!