灰度化
注释写的很清楚。这里就不一一详细介绍
但是灰度化这里要注意一下就是
data1 = (uchar)(ColorImage->imageData[i *ColorImage->widthStep+j* 3 + 0]);//blue
这行代码里头,一开始不太理解为什么有widthStep
找了一些大家写的代码发现,只要是灰度化就一定会有这个代码的
现在大概理解了,这句话的意思就是
opencv iplimage格式直接访问内存读取像素
一定要高*widthStep
从网上找了一段话,虽然目前不太理解但是记录一下、
看了一些博客,总结一下就是
width表示图像的每行像素数,
widthStep表示存储一行像素需要的字节数,widthStep必须是4的倍数,从而实现字节对齐,有利于提高运算速度。
如果8U单通道图像宽度为3,那么widthStep是4,加一个字节补齐。
这个图像的一行需要4个字节,只使用前3个,最后一个空着。
也就是一个宽3高3的图像的imageData数据大小为4*3=12字节。
【注】:不同数据类型长度的图像,widthStep也不相同;
widthStep的值的计算有两种情况:
①当(width*3)%4=0,这时width*3=widthStep;
②当(width*3)%4 !=0,此时widthStep=(width/4+1)*3。
Mat的数据并不是字节对齐的;
关于图像失真的原因分析:
当width为偶数时,widthstep与width*nchannels相等,但当width为奇数时,就会填充一个单位像素的长度使widthstep成为偶数。看了帖子,我也找到了出错的原因,我就马上修改程序。呵呵,结果正常显示了。只要把读取数据的i*width+j改为i*widthstep+j就可以了。
width是图像宽度,可为任意值;widthstep是行字节数,应该是4的倍数,不一定等于width,nchannels为图像通道数。 #define WIDTHBYTES(bits) (((bits)+31)/32*4) 看看这个公式你就明白
width表示图像的每行像素数,widthStep表示存储一行像素需要的字节数。
在OpenCV里边,widthStep必须是4的倍数,从而实现字节对齐,有利于提高运算速度。
如果8U单通道图像宽度为3,那么widthStep是4,加一个字节补齐。这个图像的一行需要4个字节,只使用前3个,最后一个空着。也就是一个宽3高3的图像的imageData数据大小为4*3=12字节。
好多都是要调用 图像->widthstep,那这个什么意思那就是调用了一个API。
根据头文件里头可以发现:
image->widthStep = (((image->width * image->nChannels *(image->depth & ~IPL_DEPTH_SIGN) + 7)/8)+ align - 1) & (~(align - 1)); (1)
其中IPL_DEPTH_SIGN的定义可以在cxtypes.h中找到,定义为:#define IPL_DEPTH_SIGN 0x80000000, align的大小为CV_DEFAULT_IMAGE_ROW_ALIGN,其大小在cxmisc.h中定义为:#define CV_DEFAULT_IMAGE_ROW_ALIGN 4,depth取8位深度。
根据(1)式,已知IPL_DEPTH_SIGN、align、depth 的大小,分别手动计算如下图像的widthStep:
图像宽度 图像通道数 计算得到的widthStep
3 3 12
3 1 4
5 3 16
5 1 8
7 3 24
7 1 8
4 3 12
4 1 4
为了进一步验证手算的正确性,我们编程实现输出widthStep的大小,程序如下:
IplImage *image_33 = cvCreateImage(cvSize(3, 3), 8, 3);
IplImage *image_31 = cvCreateImage(cvSize(3, 3), 8, 1);
IplImage *image_53 = cvCreateImage(cvSize(5, 3), 8, 3);
IplImage *image_51= cvCreateImage(cvSize(5, 3), 8, 1);
IplImage *image_73 = cvCreateImage(cvSize(7, 3), 8, 3);
IplImage *image_71 = cvCreateImage(cvSize(7, 3), 8, 1);
printf("%d, %d, %d, %d, %d, %d", image_33->widthStep,image_31->widthStep,
image_53->widthStep,image_51->widthStep,image_73->widthStep,image_71->widthStep);
运行结果为:12, 4, 16, 8, 24, 8, 与手动计算结果相同。
灰度化的代码如下,下一步高斯滤波
#include<opencv2\opencv.hpp>
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\imgproc\imgproc.hpp>
#include<iostream>
#include<opencv2\core\core.hpp>
#include<stdio.h>
#include<cv.h>
using namespace cv;
int main()
{ //读图像
IplImage * ColorImage = cvLoadImage("D:\\anzhuang\\vsworkspace\\canny2\\2.png", 1);
//判断是否读图成功
if (ColorImage == NULL)
{
printf("image read error");
return 0;
}
//命名窗口,显示窗口
cvNamedWindow("Sourceing",0);
cvShowImage("Sourceing", ColorImage);
//定义一个数组
IplImage * OpenCvGrayImage;
//用CreateImage函数创建图像首地址,并分配存储空间,将首地址赋给刚刚定义的数组
OpenCvGrayImage = cvCreateImage(cvGetSize(ColorImage), ColorImage->depth, 1);
//灰度化,通过指针方式进行读取,显示彩色图像三个通道的图片,并根据RGB转换为灰度图像
//因为图像是矩阵,所以有两个for
float data1, data2, data3;
for (int i = 0; i < ColorImage->height; i++)
{
for (int j = 0; j < ColorImage->width; j++)
{
data1 = (uchar)(ColorImage->imageData[i *ColorImage->widthStep+j* 3 + 0]);//blue
data2 = (uchar)(ColorImage->imageData[i *ColorImage->widthStep+j * 3 + 1]);//green
data3 = (uchar)(ColorImage->imageData[i *ColorImage->widthStep+j * 3 + 2]);//red
OpenCvGrayImage->imageData[i*OpenCvGrayImage->widthStep + j] = (uchar)(0.114*data1 + 0.587*data2 + 0.299*data3);
}
}
//命名窗口,并显示处理
cvNamedWindow("GrayImage",0);
cvShowImage("GrayImage", OpenCvGrayImage);
cvWaitKey(0);
cvDestroyWindow("GrayImage");
。