嵌入式系统 视频 图像捕获
回帖(2)
2019-8-8 17:26:44
2019-8-8 17:26:48
具体的这个过程由于篇幅关系本文将不做具体阐述,读者可以查阅本文的参考文献3。在上述的过程中主要考虑的问题是内存的映射问题。为了读取数据首先需要将显示设备的地址映射到系统地址上来,这需要调用函数mmap()。该函数返回的地址就是存放图像数据的地址。每一帧图像都偏移固定的长度。而摄像头取得图像会包含若干帧。这样通过周而复始的进行就可以将图像数据捕获下来。具体过程和涉及到的函数如下所示:
打开设备文件:intdevice=open("/dev/v4l/video0",O_RDWR);
内存映射:char*memoryMap=(char*)mmap(0,memoryBuffer.size,PROT_READ|PROT_WRITE,MAP_SHARED,device,0);
图像数据memoryMap+memoryBuffer.offsets[bufferIndex]
图2
3.2图像格式的转换。
通过上文所述取得图像数据后,实际就是一块地址。这时就可以进行各种图像处理或图像识别。问题的关键是图像数据是如何放置的。一般情况下,在计算机中一个像素点是由R、G、B三种颜色表示的。当然还存在其它的模式如PAL等。但大多数为RGB模式。即使是RGB模式也存在很多种情况,如每一个像素由8个bit组成,这时R、G、B三种颜色的位数分别3、3、2。如果每一个像素由12个bit组成,则R、G、B三种颜色的位数分别4、4、4。如果每一个像素由16个bit组成,则R、G、B三种颜色的位数存在两种情况分别5、5、5,最高位舍弃,另一种情况为5、6、5。最容易处理、同时也是最常见的是24个bit组成的,这时R、G、B三种颜色的位数分别8、8、8。
在各种图像处理的程序中往往需要在两种格式之间转换。由于在笔者所采用的设备中,采集到的图像为24位,而显示设备为12位,这就需要在两种格式之间转换。至于怎样将图像数据显示到屏幕上在后文中阐述,下面将主要阐述如何在24位和12位之间转换。整个过程如图3所示。
图3
首先需要明确计算机中处理的数据是8位为基本单位的。所以,一个像素12位的图象格式可以通过两个像素24位为基本单位进行描述。其次,应该明确的是在从8位数据到4位数据的转换中取得8位数据中的高4位,frame[index*3]&0xF0);然后再取得下一个8位的高4位;左移4位和前面的数据取并,frame[index*3]&0xF0)|((frame[index*3+1]&0xF0)>>4。实现的代码如下:
*(fbp)=(frame[index*3]&0xF0)|((frame[index*3+1]&0xF0)>>4);
*(fbp+1)=(frame[index*3+2]&0xF0)|(frame[(index+1)*3]&0xF0>>4);
*(fbp+2)=(frame[(index+1)*3+1]&0xF0)|(frame[(index+1)*3+2]&0xF0>>4);
在这段代码中*(fbp)、*(fbp+1)、*(fbp+2)这三个8位实际上两个像素的图像数据。这就实现了24位的图像数据到12位的图像数据的转换。
4应用framebuffer进行图像的显示
为了将程序中图像数据显示在设备的液晶屏幕上,需要读出现实设备的地址并将其映射到系统内存空间上,然后再将图像数据写到映射后的地址空间上。[5]
首先需要计算出屏幕内存空间的字节数,计算公式为:
屏幕内存空间的字节数=像素的个数╳每个像素占用的字节
其中像素的个数是行和列的乘积,而行和列的数值以及每个像素占用的字节数值可以通过函数ioctl()取得或设置。下述代码为打开framebuffer,读取屏幕的可设置信息,并计算屏幕内存空间的字节数的过程。
structfb_var_screeninfovinfo;
intFraBuf=open("/dev/0",O_RDWR);
ioctl(fbfd,FBIOGET_VSCREENINFO,&vinfo);
longintscreensize=vinfo.xres*vinfo.yres*vinfo.bits_per_pixel;
取得屏幕的大小后,将打开的设备FraBuf得到的内存空间映射到系统中,如下所示,
char*fbpfbp=(char*)mmap(0,screensize,PROT_READ|PROT_WRITE,MAP_SHARED,fbfd,0);
然后将前文得到的数据赋值即可。上面的函数的具体意义,读者可以参看相关技术文档,限于篇幅本文没有阐述。这个过程和前文所述的捕获过程是相反的过程。
5简单字符的屏幕显示技术
在数字图像处理过程中,为了将处理后结果或数字显示出来,可以在屏幕上开个区域进行显示。如若字体较多需要字库,如果仅仅是简单的数字可以采用像素描绘的方法。本文作者就是采用后者输出了数字。如数字“1”的描绘程序如下:
x=160;
for(y=210;y<230;y++){
location=(x+vinfo.xoffset)*(vinfo.bits_per_pixel/8)+y+vinfo.yoffset)*finfo.line_length;
*(fbp+location)=10;
*(fbp+location+1)=10;
*(fbp+location+2)=10;
}
其中x、y为屏幕的位置,而fbp就是前文打开的设备。
6结束语
本文采用的设备是基于SAMSUNG公司的ARM9芯片S3C2410,由于篇幅的限制本文没有具体阐述整个系统,集中阐述了视频图像数据的捕获和显示,在这一过程中存在许多细节问题,限于篇幅没有阐述。
具体的这个过程由于篇幅关系本文将不做具体阐述,读者可以查阅本文的参考文献3。在上述的过程中主要考虑的问题是内存的映射问题。为了读取数据首先需要将显示设备的地址映射到系统地址上来,这需要调用函数mmap()。该函数返回的地址就是存放图像数据的地址。每一帧图像都偏移固定的长度。而摄像头取得图像会包含若干帧。这样通过周而复始的进行就可以将图像数据捕获下来。具体过程和涉及到的函数如下所示:
打开设备文件:intdevice=open("/dev/v4l/video0",O_RDWR);
内存映射:char*memoryMap=(char*)mmap(0,memoryBuffer.size,PROT_READ|PROT_WRITE,MAP_SHARED,device,0);
图像数据memoryMap+memoryBuffer.offsets[bufferIndex]
图2
3.2图像格式的转换。
通过上文所述取得图像数据后,实际就是一块地址。这时就可以进行各种图像处理或图像识别。问题的关键是图像数据是如何放置的。一般情况下,在计算机中一个像素点是由R、G、B三种颜色表示的。当然还存在其它的模式如PAL等。但大多数为RGB模式。即使是RGB模式也存在很多种情况,如每一个像素由8个bit组成,这时R、G、B三种颜色的位数分别3、3、2。如果每一个像素由12个bit组成,则R、G、B三种颜色的位数分别4、4、4。如果每一个像素由16个bit组成,则R、G、B三种颜色的位数存在两种情况分别5、5、5,最高位舍弃,另一种情况为5、6、5。最容易处理、同时也是最常见的是24个bit组成的,这时R、G、B三种颜色的位数分别8、8、8。
在各种图像处理的程序中往往需要在两种格式之间转换。由于在笔者所采用的设备中,采集到的图像为24位,而显示设备为12位,这就需要在两种格式之间转换。至于怎样将图像数据显示到屏幕上在后文中阐述,下面将主要阐述如何在24位和12位之间转换。整个过程如图3所示。
图3
首先需要明确计算机中处理的数据是8位为基本单位的。所以,一个像素12位的图象格式可以通过两个像素24位为基本单位进行描述。其次,应该明确的是在从8位数据到4位数据的转换中取得8位数据中的高4位,frame[index*3]&0xF0);然后再取得下一个8位的高4位;左移4位和前面的数据取并,frame[index*3]&0xF0)|((frame[index*3+1]&0xF0)>>4。实现的代码如下:
*(fbp)=(frame[index*3]&0xF0)|((frame[index*3+1]&0xF0)>>4);
*(fbp+1)=(frame[index*3+2]&0xF0)|(frame[(index+1)*3]&0xF0>>4);
*(fbp+2)=(frame[(index+1)*3+1]&0xF0)|(frame[(index+1)*3+2]&0xF0>>4);
在这段代码中*(fbp)、*(fbp+1)、*(fbp+2)这三个8位实际上两个像素的图像数据。这就实现了24位的图像数据到12位的图像数据的转换。
4应用framebuffer进行图像的显示
为了将程序中图像数据显示在设备的液晶屏幕上,需要读出现实设备的地址并将其映射到系统内存空间上,然后再将图像数据写到映射后的地址空间上。[5]
首先需要计算出屏幕内存空间的字节数,计算公式为:
屏幕内存空间的字节数=像素的个数╳每个像素占用的字节
其中像素的个数是行和列的乘积,而行和列的数值以及每个像素占用的字节数值可以通过函数ioctl()取得或设置。下述代码为打开framebuffer,读取屏幕的可设置信息,并计算屏幕内存空间的字节数的过程。
structfb_var_screeninfovinfo;
intFraBuf=open("/dev/0",O_RDWR);
ioctl(fbfd,FBIOGET_VSCREENINFO,&vinfo);
longintscreensize=vinfo.xres*vinfo.yres*vinfo.bits_per_pixel;
取得屏幕的大小后,将打开的设备FraBuf得到的内存空间映射到系统中,如下所示,
char*fbpfbp=(char*)mmap(0,screensize,PROT_READ|PROT_WRITE,MAP_SHARED,fbfd,0);
然后将前文得到的数据赋值即可。上面的函数的具体意义,读者可以参看相关技术文档,限于篇幅本文没有阐述。这个过程和前文所述的捕获过程是相反的过程。
5简单字符的屏幕显示技术
在数字图像处理过程中,为了将处理后结果或数字显示出来,可以在屏幕上开个区域进行显示。如若字体较多需要字库,如果仅仅是简单的数字可以采用像素描绘的方法。本文作者就是采用后者输出了数字。如数字“1”的描绘程序如下:
x=160;
for(y=210;y<230;y++){
location=(x+vinfo.xoffset)*(vinfo.bits_per_pixel/8)+y+vinfo.yoffset)*finfo.line_length;
*(fbp+location)=10;
*(fbp+location+1)=10;
*(fbp+location+2)=10;
}
其中x、y为屏幕的位置,而fbp就是前文打开的设备。
6结束语
本文采用的设备是基于SAMSUNG公司的ARM9芯片S3C2410,由于篇幅的限制本文没有具体阐述整个系统,集中阐述了视频图像数据的捕获和显示,在这一过程中存在许多细节问题,限于篇幅没有阐述。
举报
更多回帖