opencv学习(六)书本《学习Opencv》(中文版)第四章的作业答案第二题(opencv3.0.0+VS2012+win7)

显示坐标很简单,但是显示RGB就必须要非常了解IPlImage结构如何获取数据了,书上讲的非常繁杂,下面仔细分析一下IPlImage结构,

opencv最重要的结构体是IplImage结构。从本质上讲,这是一个CvMat对象,但它还有一些其他成员变量将矩阵解释为图像

IplImage结构具体定义如下:

typedef struct _IplImage
{
	int nSize; /* IplImage大小 */
	int ID; /* 版本 (=0)*/
	int nChannels; /* 大多数OPENCV函数支持1,2,3 或 4 个通道 */
	int alphaChannel; /* 被OpenCV忽略 */
	int depth; /* 像素的位深度,主要有以下支持格式: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U,IPL_DEPTH_16S, IPL_DEPTH_32S,
	IPL_DEPTH_32F 和IPL_DEPTH_64F */
	char colorModel[4]; /* 被OpenCV忽略 */
	char channelSeq[4]; /* 同上 */
	int dataOrder; /* 0 - 交叉存取颜色通道, 1 - 分开的颜色通道.
	只有cvCreateImage可以创建交叉存取图像 */
	int origin; /*图像原点位置: 0表示顶-左结构,1表示底-左结构 */
	int align; /* 图像行排列方式 (4 or 8),在 OpenCV 被忽略,使用 widthStep 代替 */
	int width; /* 图像宽像素数 */
	int height; /* 图像高像素数*/
	struct _IplROI *roi; /* 图像感兴趣区域,当该值非空时,
	只对该区域进行处理 */
	struct _IplImage *maskROI; /* 在 OpenCV中必须为NULL */
	void *imageId; /* 同上*/
	struct _IplTileInfo *tileInfo; /*同上*/
	int imageSize; /* 图像数据大小(在交叉存取格式下ImageSize=image->height*image->widthStep),单位字节*/
	char *imageData; /* 指向排列的图像数据 */
	int widthStep; /* 排列的图像行大小,以字节为单位 */
	int BorderMode[4]; /* 边际结束模式, 在 OpenCV 被忽略*/
	int BorderConst[4]; /* 同上 */
	char *imageDataOrigin; /* 指针指向一个不同的图像数据结构(不是必须排列的),是为了纠正图像内存分配准备的 */
} IplImage;

IplImage结构体是整个OpenCV函数库的基础,在定义该结构变量时需要用到函数cvCreatImage,变量定义方法如下:

IplImage* src= cvCreateImage(cvSize(400,300), IPL_DEPTH_8U,3);
上句定义了一个IplImage指针变量src,图像的大小是400×300,图像颜色深度8位,3通道图像。


关键在这一句:

uchar* bgr = (uchar*)Img->imageData + Img->widthStep * point.y + Img->nChannels * point.x;//获取某个像素点
大神的分析:

你应该是刚学opncv吧,widthstep是指图像每行所占的字节数,主要要和width区别,width是指每行所含的像素个数,但是一个像素也可能占一个字节,也可能占三个字节或者四个.imagedata是指向存储图像像素值数组的指针,内容是这个数组的首地址,point.y指的是像素点的行坐标,所以Img->imageData + Img->widthStep*point.y便是该像素点所在行的首地址,然后再加上该像素点所在的列,即point.x,就得到了该像素点的地址.


真大神:http://www.cnblogs.com/uriboyka/archive/2013/04/23/3038788.html

假设你要访问第K通道,第i行,第j列的像素

一 间接访问:(通用,但效率低,可访问任意格式的图像)

对于单通道字节型图像:

IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); 
CvScalar s;
 s=cvGet2D(img,i,j); /* get the (j,i) pixel value, 注意cvGet2D与cvSet2D中坐标参数的顺序与其它opencv函数坐标参数顺序恰好相反.
本函数中i代表y轴,即height;j代表x轴,即weight.也即先cvGet2D的第二个参数i表示行号,第三个参数j表示列号。
而元素的坐标值的(j,i) printf("intensity=%f\n",s.val[0]);*/
 s.val[0]=111; 
cvSet2D(img,i,j,s); // set the (j,i) pixel value设置像素值

对于多通道字节型/浮点型图像:

IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3); 
CvScalar s; 
s=cvGet2D(img,i,j); // get the (j,i) pixel value 
printf("B=%f, G=%f, R=%f\n",s.val[0],s.val[1],s.val[2]); 
s.val[0]=111; 
s.val[1]=111; 
s.val[2]=111; 
cvSet2D(img,i,j,s); // set the (j,i) pixel value

二 直接访问:(效率高,但容易出错)

对于单通道字节型图像:

1 IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); 
2 ((uchar *)(img->imageData + i*img->widthStep))[j]=111;
对于多通道字节型图像:

1 IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3); 
2 ((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 0]=111; // B 
3 ((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 1]=112; // G 
4 ((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 2]=113; // R

对于多通道浮点型图像:

1 IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3); 
2 ((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 0]=111; // B 
3 ((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 1]=112; // G 
4 ((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 2]=113; // R

 

三 基于指针的直接访问:(简单高效)

对于单通道字节型图像:

1 IplImage* img  = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); 
2 int height      = img->height; 
3 int width       = img->width; 
4 int step        = img->widthStep; 
5 uchar* data    = (uchar *)img->imageData; data[i*step+j] = 111;

对于多通道字节型图像:

复制代码
1 IplImage* img  = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3); 
2 int height      = img->height; 
3 int width       = img->width; 
4 int step        = img->widthStep; 
5 int channels   = img->nChannels; 
6 uchar* data    = (uchar *)img->imageData; 
7 data[i*step+j*channels+k] = 111;
复制代码

对于多通道浮点型点型图像(假设图像数据采用4字节(32位)行对齐方式):

复制代码
1 IplImage* img  = cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3); 
2 int height     = img->height; 
3 int width      = img->width; 
4 int step       = img->widthStep; 
5 int channels = img->nChannels; 
6 float * data    = (float *)img->imageData; 
7 data[i*step+j*channels+k] = 111;
复制代码

由此可以知道第二题找到BGR像素值就不难了

源码如下:

#include "cv.h"  
#include "highgui.h"  
#include<string>
#include<iostream>
#include<cstdio>
using namespace std;

void my_mouse_callback(int event, int x, int y, int flags, void* param);  
void putText(IplImage* image, CvPoint point); 
void putText2(IplImage* image, CvPoint point); 
CvPoint point;

int main(int argc, char** argv)
{  
	cvNamedWindow("taenshow",CV_WINDOW_AUTOSIZE); 
    IplImage* image = cvLoadImage(argv[1]);  
    cvShowImage("taenshow",image);
	while(1)
	{
		cvSetMouseCallback("taenshow",my_mouse_callback,(void*)image);  
		char c = (char)cvWaitKey(33);
        if( c == 27 ) break;  
	}
    return 0;  
}  
  
void my_mouse_callback(int event, int x, int y, int flags, void* param)  
{  
    IplImage* img = (IplImage*)param;  
	switch(event)
	{
		case CV_EVENT_LBUTTONDOWN :
			point.x = x;
			point.y = y;
			putText(img,point);
			break;
		case CV_EVENT_RBUTTONDOWN:
			point.x=x;
			point.y=y;
			putText2(img,point);
			break;  
	}
}  
  
void putText(IplImage* image, CvPoint point)  
{  
	char color[100],px[100],py[100];
	_itoa(point.x,px,10);//整数转换成字符串;
	_itoa(point.y,py,10);//整数转换成字符串;
	strcpy(color,"("); 
	strcat(color,px);
	strcat(color,",");
	strcat(color,py);
	strcat(color,")"); 
	CvFont font ;
    cvInitFont(&font,CV_FONT_HERSHEY_SIMPLEX,0.5,0.5,0);  
    cvPutText(image,color,point,&font,cvScalar(0,0,255));  //BGR
    cvShowImage("taenshow",image);
}

void putText2(IplImage* Img,CvPoint point)//鼠标左键显示颜色值RGB
{     //定义bgr接受像素颜色信息 
	uchar* bgr = (uchar*)Img->imageData + Img->widthStep * point.y + Img->nChannels * point.x;//获取某个像素点,直接访问
//	CvScalar s = cvGet2D(Img,point.x,point.y);//获取像素点为(x,y)点的BGR的值,貌似有问题,在某些像素点报错?
	char color[100];//显示颜色值字符串
	char cb[16],cg[16],cr[16];//单个颜色值字符串  
//	sprintf_s(cb,"%f",bgr[0]);//double转string
//	sprintf_s(cg,"%f",bgr[1]);
//	sprintf_s(cr,"%f",bgr[2]);
	_itoa(bgr[0],cb,10);//int转string
	_itoa(bgr[1],cg,10);
	_itoa(bgr[2],cr,10);   
//	_itoa(s.val[0],cb,10);
//	_itoa(s.val[1],cg,10);
//	_itoa(s.val[2],cr,10); 
	strcpy(color,"("); 
	strcat(color,cb);
	strcat(color,",");
	strcat(color,cg);
	strcat(color,",");
	strcat(color,cr);
	strcat(color,")"); 
	//初始化显示字体
	CvFont font;
    cvInitFont(&font,CV_FONT_HERSHEY_SIMPLEX,0.5,0.5);      //颜色信息显示
    cvPutText(Img,color,cvPoint(point.x,point.y),&font,CV_RGB(255,255,0)); //BGR
    cvShowImage("taenshow",Img);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值