数字图像处理不得不知的点(3)

来源:互联网 发布:java线上培训班 编辑:程序博客网 时间:2024/05/17 01:13

九、widthStep 是否等于width*nChannels

哈哈,打了自己的脸,前面的blog还说相等呢,待会儿去改了。

这不遇到问题了嘛。

当且仅当 (width*nChannels%4==0的时候,等式成立。

相关连接:

建议看:

http://blog.csdn.net/xidianzhimeng/article/details/16845097

http://blog.csdn.net/timidsmile/article/details/7386322

然而我先看的是:

http://blog.csdn.net/zhirom/article/details/7487159

这个太长了就没看:

http://blog.sina.com.cn/s/blog_7ff488630100z25p.html


但是可以肯定一点。就是 如果在进行某些操作的时候尽量避开widthStep。嗯...这个。。。要辩证的来看,如果为了具体找到某一行的首地址,那么用且只能用widthStep,但是如果用widthStep来限定循环次数,那么这个就会出现很多需要花时间来厘清的问题。

关于使用

我觉得只要是不操作到widthStep的末尾就一切安全。比如要找到中间的某行,一旦触碰到了widthStep的末尾问题就有可能发生


【吐槽:之所以要写这样一个东西也是基于我一搜什么基本啊,入门啊,全tm是《学习opencv中文版》连接。要么抄录,要么是代码的集合,错误都原封不动的抄,有点儿意思嘛。。。】

IplImage* myPicAdd(IplImage* src1, IplImage* src2){//先考虑通道数相同的情况。int height = src1->height;if (src1->height < src2->height){height = src2->height;}int width = src1->width + src2->width;IplImage * img = cvCreateImage(cvSize(width, height), src1->depth, src1->nChannels);if (src1->nChannels == src2->nChannels){for (int i = 0; i<img->height; i++){for (int j = 0;j<img->widthStep; j++){//使用widthStep时候会有问题if (j < src1->widthStep){if (i < src1->height)img->imageData[img->widthStep *i + j] = src1->imageData[src1->widthStep *i + j];elseimg->imageData[img->widthStep *i + j] = 0;}else{if (i < src2->height)img->imageData[img->widthStep *i + j] = src2->imageData[src2->widthStep *i + j - src1->widthStep];elseimg->imageData[img->widthStep *i + j] = 0;}}}}return img;}

明杰同学帮忙修正版:

IplImage* myPicAdd2(IplImage* src1, IplImage* src2){//先考虑通道数相同的情况。int height = src1->height;if (src1->height < src2->height){height = src2->height;}int width = src1->width + src2->width;IplImage * img = cvCreateImage(cvSize(width, height), src1->depth, src1->nChannels);if (src1->nChannels == src2->nChannels){for (int i = 0; i<img->height; i++){//200for (int j = 0; j<img->width; j++){//使用width,就少了对通道的设定,下面w就是单独操纵每一个通道if (j<src1->width){for (int w = 0; w < 3; w++)//每个通道在单独限制一下,不过这样的话,单通道可能就会出问题{//图像数据元素首地址, 行首地址,      列地址  每个通道*(img->imageData + i*(img->widthStep) + j*3 + w) = *(src1->imageData + i*(src1->widthStep) + j*3 + w);}}else{for (int w = 0; w < 3; w++){*(img->imageData + i*(img->widthStep) + j*3 + w) = *(src2->imageData + i*(src2->widthStep) + (j - src1->width)*3 + w);}}}}}return img;}

压合原型:

void myPicAdd(IplImage* src1, IplImage* src2, IplImage* dest){for (int i = 0; i< src1->height; i++){for (int j = 0; j<dest->widthStep; j++){if (j<src1->widthStep)dest->imageData[dest->widthStep *i + j] = src1->imageData[src1->widthStep *i + j];else dest->imageData[dest->widthStep *i + j] = src2->imageData[src2->widthStep *i + j-src1->widthStep];}}}

他每一步的推导与演变:

http://www.cnblogs.com/letben/p/5462356.html


不相等的本质:来源于内存对齐:

opencv里面觉得每行四个字节,的这种记录方式,很合适,可以最大限度的利用内存

这个可以参考:

十一、什么是内存对齐?

http://www.cnblogs.com/letben/p/5240356.html

 

然而为什么采用4,我才是因为int的缘故吧,然而又并解释不了double,哎?~忽然想起来了float是不是也是4个字节?那就解释通了,这个结构里面貌似并没有使用double。所以接下来就是要看一下IplImage的源码,看看里面的结构了。

types_c.h 里面的 第465510行,可以发现里面除了int就是char charName[4],如果参考了上面的博客的话就会发现,它是并且必须是4的整数倍。也根本没用到double

所以这么一对齐,结果就出来了。

 

typedef struct _IplImage

{

    int  nSize;             /* sizeof(IplImage) */

    int  ID;                /* version (=0)*/

    int  nChannels;         /* Most of OpenCV functions support 1,2,3 or 4 channels */

    int  alphaChannel;      /* Ignored by OpenCV */

    int  depth;             /* Pixel depth in bits: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16S,

                               IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F are supported.  */

    char colorModel[4];     /* Ignored by OpenCV */

    char channelSeq[4];     /* ditto */

    int  dataOrder;         /* 0 - interleaved color channels, 1 - separate color channels.

                               cvCreateImage can only create interleaved images */

    int  origin;            /* 0 - top-left origin,

                               1 - bottom-left origin (Windows bitmaps style).  */

    int  align;             /* Alignment of image rows (4 or 8).

                               OpenCV ignores it and uses widthStep instead.    */

    int  width;             /* Image width in pixels.                           */

    int  height;            /* Image height in pixels.                          */

    struct _IplROI *roi;    /* Image ROI. If NULL, the whole image is selected. */

    struct _IplImage *maskROI;      /* Must be NULL. */

    void  *imageId;                 /* "           " */

    struct _IplTileInfo *tileInfo;  /* "           " */

    int  imageSize;         /* Image data size in bytes

                               (==image->height*image->widthStep

                               in case of interleaved data)*/

    char *imageData;        /* Pointer to aligned image data.         */

    int  widthStep;         /* Size of aligned image row in bytes.    */

    int  BorderMode[4];     /* Ignored by OpenCV.                     */

    int  BorderConst[4];    /* Ditto.                                 */

    char *imageDataOrigin;  /* Pointer to very origin of image data

                               (not necessarily aligned) -

                               needed for correct deallocation */

}

IplImage;

 

typedef struct _IplTileInfo IplTileInfo;

 

typedef struct _IplROI

{

    int  coi; /* 0 - no COI (all channels are selected), 1 - 0th channel is selected ...*/

    int  xOffset;

    int  yOffset;

    int  width;

    int  height;

}

IplROI;



十、opencv里面三个颜色的排序是BGR而不是RGB。

依然是上面拼接的时候,发现色相差值:


本应该是 绿的变成了蓝的,本应该是蓝的变成了红的。

方式一:

   RGB

RGBR

方式二:

      BGR

BGRBGR

当时拼接的正确结果是头一幅图是310个像素宽,这样理论上widthStep是930,由于上面的内存对齐结果是932.打断点的时候也是这样一个结果。所以如果差值差两个字节,颜色的表现就不可能是RGB,至于是什么:

http://zhidao.baidu.com/link?url=szNAFpk-myabfBxnRo7eXGZMYY6BHtgvJsou_207gOOXkWSbhGM4feEbPGTCMNi-R6GeSrNZfUb9cMp-p1_r2a

至于为什么。。。囧囧囧

可能原来有个什么小故事吧。。。

但是我们并不需要知道   囧囧囧。

你用到的 CvScalar也是BGR的所以opencv里面就是 BGR的这样一套顺序。



0 0
原创粉丝点击