九、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; iheight; i++){
for (int j = 0;jwidthStep; j++){//使用widthStep时候会有问题
if (j < src1->widthStep)
{
if (i < src1->height)
img->imageData[img->widthStep *i + j] = src1->imageData[src1->widthStep *i + j];
else
img->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];
else
img->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; iheight; i++){//200
for (int j = 0; jwidth; j++){//使用width,就少了对通道的设定,下面w就是单独操纵每一个通道
if (jwidth)
{
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; jwidthStep; j++){
if (jwidthStep)
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 里面的 第465到510行,可以发现里面除了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的这样一套顺序。