本程序源于一个想法,如何将图片直接上传到FTP。能想到的一个可行的方法就是在Ftp站点下新建一个文件,打开文件并传输数据。吸取了OpenCV教程一书例4-4与例4-5及相关知识。本项目由以下两个有机组成部分构成:1、将图像的颜色数据存入文件2、从文件读取要求区域的图像的颜色数据
本项目由以下两个有机组成部分构成:
1、将图像的颜色数据存入文件
2、从文件读取要求区域的图像的颜色数据
#include " highgui.h "
#include " stdlib.h "
int main( int argc, char ** argv )
... {
IplImage* img = 0;
img = cvLoadImage("20080514150135664.jpg",CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);
CvFileStorage* fs = cvOpenFileStorage("example.yml",0 , CV_STORAGE_WRITE);
cvWrite(fs , "Image" ,img , cvAttrList(0,0));
system("PAUSE");
cvReleaseFileStorage(&fs);
cvReleaseImage(&img);
return 0;
}
#include < highgui.h >
#include " cxcore.h "
int main( int argc, char ** argv )
... {
CvSeq* seq;
CvSeqReader reader;
CvPoint point = cvPoint(100,100);
CvSize size = cvSize(400,350);
IplImage* img = cvCreateImage(size,IPL_DEPTH_8U,3);
uchar *picData ;
int step;
int channels;
picData = (uchar*)img->imageData;
channels = img->nChannels;
step = img->widthStep/sizeof(uchar);
CvFileStorage* fs = cvOpenFileStorage( "example.yml", 0, CV_STORAGE_READ );
CvFileNode* parent = cvGetFileNodeByName( fs, 0, "Image" );
CvFileNode* data = cvGetFileNodeByName( fs, parent, "data" );
CvFileNode* imgWidth = cvGetFileNodeByName( fs, parent, "width" );
CvFileNode* imgHeight = cvGetFileNodeByName( fs, parent, "height" );
int width,height;
width = imgWidth->data.i;
height = imgHeight->data.i;
seq = data->data.seq;
cvStartReadSeq( seq, &reader, 0 );
int total = seq->total;
int value;
int i,j,k;
for(i=0;i<size.height + point.y;i++)
...{
for(j=0;j<width;j++)
...{
for(k = 0;k<channels;k++)
...{
CvFileNode* pt = (CvFileNode*)reader.ptr;
if(j<size.width+point.x&&j>=point.x&&i>=point.y)
...{
value = pt->data.i;
picData[(i-point.y)*step+(j-point.x)*channels+k] = value;
}
CV_NEXT_SEQ_ELEM(seq->elem_size, reader );
}
}
}
cvNamedWindow("region of image",CV_WINDOW_AUTOSIZE);
cvShowImage("region of image",img);
cvWaitKey(0);
cvReleaseImage(&img);
cvDestroyWindow("region of image");
return 0;
}
example.yml的大体格式如下
image: !!opencv-image
width: 640
height: 480
origin: top-left
layout: interleaved
dt: "3u"
data: [ 128, 160, 143, 131, 160, 144, 134, 158, 146, 135, 157, 145,
...
]
虽然程序段很简短,但我也是苦做了一天完成的成果。其间绕了不少弯路,不过也对很多知识点加深了了解。如下:
1、访问图像元素时的坐标(i,j)分别指的是纵坐标和横坐标。与通常的坐标表示习惯不一样。据我的理解,这样做是因为图像数据的读写以origin结构的起始点一行一行来的,所以IplImage的结构才只有widthStep,而没有heighthStep。
2、还有一个有趣的地方就是CV_NEXT_SEQ_ELEM宏的使用
/* move reader position forward */
#define CV_NEXT_SEQ_ELEM( elem_size, reader ) /
{ /
if( ((reader).ptr += (elem_size)) >= (reader).block_max ) /
{ /
cvChangeSeqBlock( &(reader), 1 ); /
} /
}
很显然根据该宏的定义,没有办法随心所欲的移动,受reader结构的block_max所限,一次没有办法移动太大的尺寸。
项目生成的yaml文件大小有4M多,原图像文件90Kb,所以没有实际意义,但是我觉得理论上的意义还是挺大的,这是个雏形,展现了如下诸多可能:
1、可以通过Ftp直接传递应用程序的数据
2、可以将图像存入自定义格式的文件中,并从该自定义文件读取图像(可以局部的载入)
3、其实是由二衍生的具体可能性就是可以局部载入很大的图片,仅仅显示你需要的部分(当然前提是你知道你需要哪部分),大大提高效率(比如地图图像文件,超过10M都是很正常的,很明显如果一次全部载入将会占用很多系统资源)
以下是网友回复的意见,摘录于下:
其实你要用ftp传输图像可以分为2步:
1. 将图像作为普通文件下载到本地
2. 读取下载的文件
如果是图像太大,需要读局部区域的图像,可以用GDAL来做。GDAL是专门用来处理
遥感图像的,对于多波段、超大影像都有很好的支持。我过段时间打算将Gdal和OpenCV
结合到一起,抽象一个CvxGdalWrap类,用GDAL完成区域IplImage格式的读写。
最后是本文文件太大的问题。如果图像比较小问题还不太严重。但是如果图像很大的话,
用文本格式可能会生成几十MB甚至几百MB大小的文件。文件太大对于读写的速度会有很大的影响,
对于网络传输的影响更大。
但是如果只是将文本转换为二进制,依然会存在很大的冗余。当然,压缩图像的话会用到很多算法。
因此,最好的方式是用现成的图像库,直接把图像保存为png或jpg等压缩格式。
-----------chai2010