关闭

openCv学习笔记(一)——数字图形的基础和结构

725人阅读 评论(1) 收藏 举报

一图像基础

 1 数字图像 又称数码图像或数位图像,是二维图像用有限数字数值像素的表示。数字图像是由模拟图像数字化得到的、以像素为基本元素的、可以用数字计算机或数字电路存储和处理的图像。    

 2. 像素  像素(或像元,Pixel)是数字图像的基本元素,像素是在模拟图像数字化时对连续空间进行离散化得到的。每个像素具有整数行(高)和列(宽)位置坐标,同时每个像素都具有整数灰度值或颜色值。 通常,像素在计算机中保存为二维整数数阻的光栅图像,这些值经常用压缩格式进行传输和储存。   

 3.通道   基本上,描述一个像素点,如果是灰度,那么只需要一个数值来描述它,就是单通道。如果一个像素点,有RGB三种颜色来描述它,就是三通道.。windows的bmp有时候是一个四通道图像,R、G、B加上一个A通道,表示透明度。  

  4.分辨率  影象清晰度或浓度的度量标准。举例来说,分辨率代表垂直及水平显示的每英寸点(dpi)的数量。BitWare 可以用普通或标准(100 乘 200 dpi)及精细分辨率(200 乘 200 dpi)发送及接收传真文档。分辨率是一个表示平面图像精细程度的概念,通常它是以横向和纵向点的数量来衡量的,表示成水平点数×垂直点数的形式。在一个固定的平面内,分辨率越高,意味着可使用的点数越多,图像越细致。

二  图像的分类   

灰度图像: 单色数字图像,其中每个像素只有一个强度值   

 多普图像:二维图像,在每个空间点或像素位置存在一个强度值向量。如果是一幅彩色图像,则该向量有三个元素   

二值图像:所有像素值要么为0要么为1的数字图像。   

标记图像:数字图像,其中的像素值是有限的字符标记。像素的字符值表示该像素做某个判定的结果。

三 图像的数据结构  

  1.矩阵       

    1.1基本概念:底层图像表示的最普通的数据结构,矩阵元素是整型的数值,对应于采样栅格中的相应像素的亮度或其他属性。这类图像数据通常是图像设备的直接输出。矩阵中的图像信息可以通过像素的坐标得到,坐标对应于行和列的标号,矩阵图像是一个完整的表示,与图像数据的内容无关。      

   1.2矩阵表示的图像:二值图像:用仅含0和1的矩阵表示;多光谱图像:可以用几个矩阵来表示,每个矩阵含有一个频带的图像;分层图像数据结构:用不同分辨率的矩阵来获得。图像的这种分层表示对于处理机阵列结构的并行计算机会是非常的方便。   

   2.链      

     2.1链码:常用来描述物体的边界,或者图像中一个像素宽度的线条。边界由其参考像素的坐标和一序号序列来定义,符号对应于几个事先定义好了方向的单位长度的线段。注意,链码本身是相对的,数据是相对于某个参考点来表示的。用链码表示图像适合基于形式语言理论的句法模式识别。     

    2.2行程编码:通常用于图像矩阵中符号串的表示。   

   3拓扑数据结构     

     3.1赋值图:是指弧、节点或两者都带有数值的图。      

      3.2区域邻接图:其中节点赌赢与区域,相邻的区域用弧连接起来。    

    4分层数据结构       

        分层数据结构可以使特殊的算法在相对较小的数据量基础上决定处理策略,只对图像中实质部分进行最精细的分辨率工作。       

        4.1金字塔:属于最简单的分层数据结构。有M型金字塔和T型金字塔。主要是描述多个图像分辨率的数据结构。       

         4.2四叉树:是对T型金字塔的改进。图像中的选择区域比其他区域在跟高的分辨率上存储,允许选择性的提取细节。

四 openCV中的基本结构      

   对于openCv中的数据结构,这里这讨论三个cvArr,cvMat和IplImage     

     4.1CvArr:一个抽象基类,CvArr* 仅仅是被用于作函数的参数,用于指示函数接收的数组类型可以不止一个,如 IplImage*, CvMat* 甚至 CvSeq*. 最终的数组类型是在运行时通过分析数组头的前4 个字节判断。     

    4.2CvMat:多通道矩阵,以下是其结构体

typedef struct CvMat
  {
  int type; /* CvMat 标识 (CV_MAT_MAGIC_VAL), 元素类型和标记 */
  int step; /* 以字节为单位的行数据长度*/
  int* refcount; /* 数据引用计数 */
  union
   {
    uchar* ptr;
    short* s;
    int* i;
    float* fl;
    double* db;
   } data; /* data 指针 */
  #ifdef __cplusplus
  union
   {
     int rows;
     int height;
   };
  union
   {
     int cols;
     int width;
   };
  #else
   int rows; /* 行数 */
   int cols; /* 列数*/
  #endif
 } CvMat;
     CvMat这个类有两部分数据。一个是matrix header,这部分的大小是固定的,包含矩阵的大小,存储的方式,矩阵存储的地址等等,如以上结构。另一个部分是一个指向矩阵包含像素值的指针。   

  4.2.1CvMat的创建和访问         

 CvMat* cvCreateMat(int rows,int cols,int type)//创建二维矩阵,其中type可以为以下几种类型(摘自http://blog.csdn.net/yang_xian521/article/details/7107786#)        

说到数据的存储,这一直就是一个值得关注的问题,Mat_<uchar>对应的是CV_8U,Mat_<uchar>对应的是CV_8U,Mat_<char>对应的是CV_8S,Mat_<int>对应的是CV_32S,Mat_<float>对应的是CV_32F,Mat_<double>对应的是CV_64F,对应的数据深度如下:

 CV_8U - 8-bit unsigned integers ( 0..255 )

CV_8S - 8-bit signed integers ( -128..127 )• CV_16U - 16-bit unsigned integers ( 0..65535 )

CV_16S - 16-bit signed integers ( -32768..32767 )

 CV_32S - 32-bit signed integers ( -2147483648..2147483647 )

CV_32F - 32-bit floating-point numbers ( -FLT_MAX..FLT_MAX, INF, NAN )

 CV_64F - 64-bit floating-point numbers ( -DBL_MAX..DBL_MAX, INF, NAN )       

  实例代码

#include<cv.h>
#include<highgui.h>
#include<iostream>
//using namespace cv;
using namespace std;
int main()
{
    //矩阵的创建
	CvMat* mat1=cvCreateMat(2,2,CV_32FC1);//创建矩阵 
	/*
    CV32FC1-有n行三列;CV32FC3 n行一列
	*/

	*((float *)CV_MAT_ELEM_PTR(*mat1,0,0))=0.1;
	*((float *)CV_MAT_ELEM_PTR(*mat1,0,1))=0.2;
	*((float *)CV_MAT_ELEM_PTR(*mat1,1,0))=0.3;
	*((float *)CV_MAT_ELEM_PTR(*mat1,1,1))=0.4;
    CvMat* mat2 = cvCreateMatHeader(5,5,CV_32FC1);//创建矩阵头信息
	CvMat mat3;
	float valus[] = {0.1,0.2,0.3,0.4};
	cvInitMatHeader(&mat3,2,2,CV_32FC1,valus);
	//矩阵中简单得到元素——1
	float mat1_elem = CV_MAT_ELEM(*mat1,float,0,0);
	float mat3_elem = CV_MAT_ELEM(mat3,float,1,1);
	cout<<mat1_elem<<endl;
	cout<<mat3_elem<<endl;
    //矩阵中恰当得到元素——2
	//累加通道中的所有元素
    float s=0.0f;
	for(int row =0;row<mat1->rows;row++)
	{
		const float* ptr = (const float *)(mat1->data.ptr+row*mat1->step);//切换行
		for(int col=0;col<mat1->cols;col++)//每行的累加和
		{
			cout<<*ptr<<" ";
			s+=*ptr++;
		}
		cout<<endl;
	}
   // float elem = CV_MAT_ELEM(*mat,float,3,2);
	//cout<<elem<<endl;
	return 0;
}

    对于以上的CvMat现在已经推出Mat类,功能强大。。。,在下一篇中介绍

   4.3 IplImge


 

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 and IPL_DEPTH_64F 可支持 */
char colorModel[4]; /* 被OpenCV忽略 */
char channelSeq[4]; /* 同上 */
int dataOrder; /* 0 - 交叉存取颜色通道, 1 - 分开的颜色通道.
cvCreateImage只能创建交叉存取图像 */
int origin; /* 0 - 顶—左结构,
1 - 底—左结构 (Windows bitmaps 风格) */
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结构来自于 Intel Image Processing Library(是其本身所具有的)。OpenCV 只支持其中的一个子集: 

alphaChannel 在OpenCV中被忽略。 
colorModel 和channelSeq 被OpenCV忽略。OpenCV颜色转换的唯一函数 cvCvtColor把原图像的颜色空间的目标图像的颜色空间作为一个参数。
dataOrder 必须是IPL_DATA_ORDER_PIXEL (颜色通道是交叉存取),然而平面图像的被选择通道可以被处理,就像COI(感兴趣的通道)被设置过一样。
align 是被OpenCV忽略的,而用 widthStep 去访问后继的图像行。 
不支持maskROI 。处理MASK的函数把他当作一个分离的参数。MASK在 OpenCV 里是 8-bit,然而在 IPL他是 1-bit。 
tileInfo 不支持。 
BorderMode和BorderConst是不支持的。每个 OpenCV 函数处理像素的邻近的像素,通常使用单一的固定代码边际模式。 
除了上述限制,OpenCV处理ROI有不同的要求。要求原图像和目标图像的尺寸或 ROI的尺寸必须(根据不同的操作,例如cvPyrDown 目标图像的宽(高)必须等于原图像的宽(高)除以2 ±1)精确匹配,而IPL处理交叉区域,如图像的大小或ROI大小可能是完全独立的。

            以上摘自文档。

#include<cv.h>
#include<highgui.h>
#include<iostream>
//using namespace cv;
using namespace std;
int main()
{
	//遍历图像,将三通道的HSV图像,在色度保持不变的情况下,设置每个点的饱和度和高度为255.
	IplImage* imge = cvLoadImage("test.jpg");
	if(!imge)
	{
	}
	IplImage* imge_result=cvCreateImage(cvGetSize(imge),imge->depth,imge->nChannels) ;
	cvCopyImage(imge,imge_result);
	for(int y=0;y<imge_result->height;y++)
	{
		uchar* ptr = (uchar *)(imge_result->imageData + y*imge_result->widthStep);
		for(int x=0;x<imge_result->width;x++)
		{
			ptr[3*x+1] = 255;
			ptr[3*x+2] = 255;
		}
	}
	cvNamedWindow("原图");
    cvNamedWindow("result");
	cvShowImage("原图",imge);
	cvShowImage("result",imge_result);
	cvWaitKey(0);
    cvReleaseImage(&imge);
	cvReleaseImage(&imge_result);
	cvDestroyWindow("原图");
	cvDestroyWindow("result");
	return 0;
}


可以说,这种方式是遍历最快的,但是要单独的找去哪一个元素效率就不行了。

其实,些这些东西,基本上全是参考的。对于结构的了解还是不行,还要继续努力呀

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:63509次
    • 积分:839
    • 等级:
    • 排名:千里之外
    • 原创:13篇
    • 转载:37篇
    • 译文:0篇
    • 评论:27条
    文章分类
    最新评论