关于IplImage的widthstep

关于IplImage的widthstep这两天编程实现同态滤波,可实现的结果却令我大跌眼镜,滤波后的图像严重发生了错位,简直分辨不出图像的内容,检查程序没有发现错误,这让我一直很郁闷。今天早上在百度上搜到一个帖子,帖子是别人转的,但原帖子的作者也遇到过这样的错误。作者说宽度为偶数的图片不会发生这样的情况,但宽度为奇数的图片就会发生上面的错误。我也拿了几张图片试验了一下,正如作者所说。究其原因,原来是IplImage的widthstep在…

大家好,又见面了,我是你们的朋友全栈君。

这两天编程实现同态滤波,可实现的结果却令我大跌眼镜,滤波后的图像严重发生了错位,简直分辨不出图像的内容,检查程序没有发现错误,这让我一直很郁闷。今天早上在百度上搜到一个帖子,帖子是别人转的,但原帖子的作者也遇到过这样的错误。作者说宽度为偶数的图片不会发生这样的情况,但宽度为奇数的图片就会发生上面的错误。我也拿了几张图片试验了一下,正如作者所说。究其原因,原来是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】

关于IplImage中widthstep的大小与width,nchannels等的关系的问题
(点击查看大图)图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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/136501.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • ubuntu16.04 安装 dstat,使用 报错「建议收藏」

    ubuntu16.04 安装 dstat,使用 报错「建议收藏」报错hairui@hadoop:~$dstatFile"/usr/bin/dstat",line119exceptgetopt.error,exc:^SyntaxError:invalidsyntaxhairui@hadoop:~$dstat程序“dstat”尚未安装。您可以使用以下命令安装:sudo…

    2022年6月18日
    35
  • java创建线程池的四种方式_线程池对象的创建方式

    java创建线程池的四种方式_线程池对象的创建方式Java通过Executors提供四种线程池,分别为:newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。newFixedThreadPool创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。newScheduledThreadPool创建一个定长线程池,支持定时及周期性任务执行。newSingl…

    2022年9月27日
    0
  • 2021年汽车修理工(初级)报名考试及汽车修理工(初级)最新解析「建议收藏」

    2021年汽车修理工(初级)报名考试及汽车修理工(初级)最新解析「建议收藏」题库来源:安全生产模拟考试一点通公众号小程序安全生产模拟考试一点通:美容师(技师)试题及解析参考答案及美容师(技师)考试试题解析是安全生产模拟考试一点通题库老师及美容师(技师)操作证已考过的学员汇总,相对有效帮助美容师(技师)复审考试学员题库来源:安全生产模拟考试一点通公众号小程序安全生产模拟考试一点通:质量员-市政方向-通用基础(质量员)考试题是安全生产模拟考试一点通总题库中生成的一套质量员-市政方向-通用基础(质量员)免费试题,安全生产模拟考试一点通上质量员-市政方向-通用基础(质量员)作业手机同步

    2022年10月2日
    0
  • Python之queue模块

    queue模块实现了多生产者,多消费者的队列。当要求信息必须在多线程间安全交换,这个模块在同步线程编程时非常有用,Queue模块实现了所有要求的锁机制。内部实现是在抢占式线程加上临时锁,但是没有涉

    2021年12月30日
    40
  • goland2021.2.1激活破解破解方法

    goland2021.2.1激活破解破解方法,https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月14日
    169
  • vmware虚拟机连不上网解决方案

    vmware虚拟机连不上网解决方案本帖来源于“百度经验”,为了方便在这里记录一下步骤1,首先,打开已经安装好的VMware,在菜单栏找到“编辑”,在弹出的下拉功能菜单中,选择“虚拟网络编辑器”。如图:2,接着,等待软件打开虚拟网络编辑器设置界面。如图:3,接着,在打开的网路编辑器界面中,选择“还原默认设置”。如图:4,接着,在弹出的提示信息框,选择“是”。如图:5,接着,等待软件自动还原网络设置重新安装新的…

    2022年6月26日
    125

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号