OpenCV里IplImage数据结构中width和widthStep极易出错的问题

 写了一个小程序,功能是将一幅图像的四周扩展若干像素,开始时的代码如下:

#include <cv.h>
#include <highgui.h>

void SpreadAround(IplImage* src,IplImage* dst,int N)
{
     int w=src->width;
     int h=src->height;
     int wp=w+2*N;
     int hp=h+2*N;
     int i,j;
     uchar* srcdata=(uchar*)src->imageData;
     uchar* dstdata=(uchar*)dst->imageData;
     for(i=0;i<hp;i++)
          for(j=0;j<wp;j++)
              dstdata[ i*wp + j]=0;
     for(i=0;i<h;i++)
      
   memcpy(dstdata+ N + wp*(i+N), srcdata + w*i, w);

}

int main(int argc, char** argv )
{
  uchar image[300]={
  0,0,0,0,0,0,0,255,255,255,255,0,0,0,0,
  0,0,0,0,0,0,255,255,255,255,255,0,0,0,0,
  0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,
  0,0,0,0,0,255,255,255,255,255,255,255,0,0,0,
  0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,
  0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,
  0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,
  0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,
  0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,
  0,0,0,0,0,0,255,255,255,255,255,255,255,255,0,
  0,0,0,0,0,0,255,255,255,255,255,255,255,0,0,
  0,0,0,0,0,255,255,255,255,255,255,255,0,0,0,
  0,0,0,0,0,255,255,255,255,255,255,255,0,0,0,
  0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,
  0,0,0,0,255,255,255,255,255,0,0,0,0,0,0,
  0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,
  0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,
  0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,
  255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 };

 IplImage* pI=cvCreateImage(cvSize(15,20),IPL_DEPTH_8U,1);
 int i,j; 

 memcpy(pI->imageData, image, 15*20);

 cvNamedWindow("原图",1);
 cvShowImage("原图",pI);
 cvWaitKey();
 IplImage* pIP=cvCreateImage(cvSize(35,40),IPL_DEPTH_8U,1);
 SpreadAround(pI,pIP,10);
 cvNamedWindow("扩展后的图像",1);
 cvShowImage("扩展后的图像",pIP);
 cvWaitKey();
 

 cvReleaseImage(&pI);
 cvReleaseImage(&pIP);
 cvDestroyWindow("原图");
 cvDestroyWindow("扩展后的图像");
 return 0;
}

       这个程序的运行结果为,两幅图像显示的并不是想要的结果,而是很奇怪的图像。

       这个问题困扰了我两天,始终想不通是为什么,最后终于看到这篇帖子(http://apps.hi.baidu.com/share/detail/17915994),找到了原因。

       对OpenCV稍有了解的同学都知道里边用于存储图像数据的IplImage,其中有两个属性非常值得关注,稍不留神就会导致错误:

      一是width属性;二是widthStep属性。

      前者是表示图像的每行像素数,后者指表示存储一行像素需要的字节数。

      在OpenCV里边,widthStep必须是4的倍数,从而实现字节对齐,有利于提高运算速度。

      如果8U单通道图像宽度为3,那么widthStep是4,加一个字节补齐。这个图像的一行需要4个字节,只使用前3个,最后一个空着。

也就是一个宽3高3的图像的imageData数据大小为4*3=12字节。

      需要注意的是,空着的那个像素并不是无效的,它仍然可以被操作,这就是导致错误的根源。

      其实原因就在于,在cvCreateImage的时候,OpenCV为实现字节对齐,使得每行数据实际有16个字节(多出一个),在使用memcpy的过程中,这些多出的字节就把对应的数据给“吃”了,因为这些数据在cvShowImage的时候并不会显示出来,这样,第二行就少一个字节,第三行少两个字节,……,所以整个图像就显示错误了!

      知道这一点后可以将程序更改如下(红色部分),这样,程序才能按我们的设想运行。

#include <cv.h>
#include <highgui.h>

void SpreadAround(IplImage* src,IplImage* dst,int N)
{
     int w=src->width;
     int h=src->height;
     int wp=w+2*N;
     int hp=h+2*N;
     int i,j;
     uchar* srcdata=(uchar*)src->imageData;
     uchar* dstdata=(uchar*)dst->imageData;
     for(i=0;i<hp;i++)
          for(j=0;j<dst->widthStep;j++)
              dstdata[i*dst->widthStep+j]=0;
     for(i=0;i<h;i++)
         memcpy(dstdata+ N + dst->widthStep*(i+N), srcdata + src->widthStep*i, w);

}

int main(int argc, char** argv )
{
  uchar image[300]={
  0,0,0,0,0,0,0,255,255,255,255,0,0,0,0,
  0,0,0,0,0,0,255,255,255,255,255,0,0,0,0,
  0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,
  0,0,0,0,0,255,255,255,255,255,255,255,0,0,0,
  0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,
  0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,
  0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,
  0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,
  0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,
  0,0,0,0,0,0,255,255,255,255,255,255,255,255,0,
  0,0,0,0,0,0,255,255,255,255,255,255,255,0,0,
  0,0,0,0,0,255,255,255,255,255,255,255,0,0,0,
  0,0,0,0,0,255,255,255,255,255,255,255,0,0,0,
  0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,
  0,0,0,0,255,255,255,255,255,0,0,0,0,0,0,
  0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,
  0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,
  0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,
  255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 };

 IplImage* pI=cvCreateImage(cvSize(15,20),IPL_DEPTH_8U,1);
 int i,j;
 for(i = 0; i<20; i++)
      memcpy(pI->imageData + pI->widthStep*i, image + 15*i, 15); 
 cvNamedWindow("d",1);
 cvShowImage("d",pI);
 cvWaitKey();
 IplImage* pIP=cvCreateImage(cvSize(35,40),IPL_DEPTH_8U,1);
 SpreadAround(pI,pIP,10);
 cvNamedWindow("dd",1);
 cvShowImage("dd",pIP);
 cvWaitKey();
 

 cvReleaseImage(&pI);
 cvReleaseImage(&pIP);
 cvDestroyWindow("d");
 cvDestroyWindow("dd");
 return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值