【摘要】 接收BMP圖片編程,完成BMP圖片翻轉(zhuǎn)、水印添加等知識(shí)點(diǎn)。
一、攝像頭練習(xí)
1.?改進(jìn)拍照程序,至少BMP圖片數(shù)據(jù)要正常,還可以將.c文件分隔成3個(gè).c文件。
24位的真彩色BMP圖片的構(gòu)造:分為3個(gè)部分。
(1)?存放BMP頭數(shù)據(jù)—主要存放BMP屬性,RGB數(shù)據(jù)偏移量
(2)?存放BMP信息數(shù)據(jù)—存放寬度、高度、顏色位數(shù)
(3)?存放BMP圖片源數(shù)據(jù)—RGB888
注意:
(1)?BMP圖片一行(寬度)的數(shù)據(jù)必須是4的倍數(shù)。
(2)?BMP圖片的源數(shù)據(jù)是從下到上,從左到右
BMP、JPG、PNG、MP4、MP3
2.?課后擴(kuò)展知識(shí): 拍照?qǐng)D片上加水印。比如:時(shí)間水印、或者自己的名字
(1)?第一種圖片水印: 圖片重疊。
(2)?在控制臺(tái)終端屏幕上使用*號(hào)打印自己名字。
要求:
(1)?添加文字水印和數(shù)字水印。比如: 添加自己的名字和日期
(2)?實(shí)現(xiàn)任意位置添加任意的水印。
(3)?實(shí)現(xiàn)縮放功能,將圖片可以任意放大和縮小。
3.?精簡(jiǎn)遠(yuǎn)程攝像頭監(jiān)控的代碼文件。
將網(wǎng)頁監(jiān)控相關(guān)的代碼文件單獨(dú)提取出來進(jìn)行編譯,實(shí)現(xiàn)遠(yuǎn)程監(jiān)控的效果。
使用gcc單獨(dú)編譯實(shí)現(xiàn)。(uvc)
分析: 程序是依靠Makefile文件已經(jīng)編譯。首先從Makefile文件入手。
主要修改的文件:mjpg_streamer.c
1.?改進(jìn)拍照程序,至少BMP圖片數(shù)據(jù)要正常,還可以將.c文件分隔成3個(gè).c文件。
24位的真彩色BMP圖片的構(gòu)造:分為3個(gè)部分。
(1)?存放BMP頭數(shù)據(jù)—主要存放BMP屬性,RGB數(shù)據(jù)偏移量
(2)?存放BMP信息數(shù)據(jù)—存放寬度、高度、顏色位數(shù)
(3)?存放BMP圖片源數(shù)據(jù)—RGB888
注意:
(1)?BMP圖片一行(寬度)的數(shù)據(jù)必須是4的倍數(shù)。
(2)?BMP圖片的源數(shù)據(jù)是從下到上,從左到右
BMP、JPG、PNG、MP4、MP3
2.?課后擴(kuò)展知識(shí): 拍照?qǐng)D片上加水印。比如:時(shí)間水印、或者自己的名字
(1)?第一種圖片水印: 圖片重疊。
(2)?在控制臺(tái)終端屏幕上使用*號(hào)打印自己名字。
要求:
(1)?添加文字水印和數(shù)字水印。比如: 添加自己的名字和日期
(2)?實(shí)現(xiàn)任意位置添加任意的水印。
(3)?實(shí)現(xiàn)縮放功能,將圖片可以任意放大和縮小。
3.?精簡(jiǎn)遠(yuǎn)程攝像頭監(jiān)控的代碼文件。
將網(wǎng)頁監(jiān)控相關(guān)的代碼文件單獨(dú)提取出來進(jìn)行編譯,實(shí)現(xiàn)遠(yuǎn)程監(jiān)控的效果。
使用gcc單獨(dú)編譯實(shí)現(xiàn)。(uvc)
分析: 程序是依靠Makefile文件已經(jīng)編譯。首先從Makefile文件入手。
任務(wù)2:漢字庫的制作與使用
需要解決的問題:
1.?如何從漢字庫里提取自己想要的點(diǎn)陣數(shù)據(jù) 。比如: 萬邦易嵌
漢字庫編碼還是GBK編碼: 有特定的公式可以計(jì)算點(diǎn)陣碼的位置。
2.?如何區(qū)分中文還有英文
數(shù)據(jù)大于0x80就是中文,其他就是英文數(shù)據(jù)。 變量必須是: 無符號(hào)類型
注意: 寫代碼需要在中文編碼的情況下編寫!
3.?英文數(shù)據(jù)該如何取模?
從空格開始到~號(hào)結(jié)束 ,連續(xù)95個(gè)數(shù)據(jù)。
2.1 BMP圖片縮放
#include
#include
int PicZoom(unsigned char *s_buff,unsigned int s_width,unsigned int s_height,unsigned char *buff,unsigned int width,unsigned int height);
void *my_memcpy(void *v_dst,const void *v_src,unsigned char c);
#pragma pack(1) /* 必須在結(jié)構(gòu)體定義之前使用,這是為了讓結(jié)構(gòu)體中各成員按1字節(jié)對(duì)齊 */
/*需要文件信息頭:14個(gè)字節(jié) */
struct BITMAPFILEHEADER
{
unsigned short bfType; //保存圖片類似。 'BM'
unsigned long bfSize; //圖片的大小
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned long bfOffBits; //RGB數(shù)據(jù)偏移地址
};
/* 位圖信息頭 */
struct BITMAPINFOHEADER { /* bmih */
unsigned long biSize; //結(jié)構(gòu)體大小
unsigned long biWidth; //寬度
unsigned long biHeight; //高度
unsigned short biPlanes;
unsigned short biBitCount; //顏色位數(shù)
unsigned long biCompression;
unsigned long biSizeImage;
unsigned long biXPelsPerMeter;
unsigned long biYPelsPerMeter;
unsigned long biClrUsed;
unsigned long biClrImportant;
};
#define NEW_FILE_NAME "new.bmp" //縮放后的新圖片名稱
#define SRC_FILE_NAME "src.bmp" //源圖片名稱
/*
圖片放大與縮小示例
*/
int main()
{
struct BITMAPFILEHEADER src_head; //源文件頭數(shù)據(jù)
struct BITMAPINFOHEADER src_info; //源文件參數(shù)結(jié)構(gòu)
struct BITMAPFILEHEADER new_head; //新文件頭數(shù)據(jù)
struct BITMAPINFOHEADER new_info; //新文件參數(shù)結(jié)構(gòu)
unsigned int new_Width; //縮放后的寬度
unsigned int new_Height; //縮放后的高度
unsigned char *new_buff; //存放新圖片的數(shù)據(jù)
unsigned char *src_buff; //存放源圖片的數(shù)據(jù)
unsigned int cnt=0;
/*1. 打開圖片文件*/
FILE *src_file=fopen(SRC_FILE_NAME,"rb");
FILE *new_file=fopen(NEW_FILE_NAME,"wb");
if(src_file==NULL||new_file==NULL)
{
printf("%s 源文件打開失敗!\r\n",SRC_FILE_NAME);
return;
}
/*2. 讀取源圖片參數(shù)*/
fread(&src_head,sizeof(struct BITMAPFILEHEADER),1,src_file);
fread(&src_info,sizeof(struct BITMAPINFOHEADER),1,src_file);
printf("源圖片尺寸:w=%d h=%d\r\n",src_info.biWidth,src_info.biHeight);
/*3. 獲取新圖片的尺寸*/
printf("輸入新圖片的寬度: ");
scanf("%d",&new_Width);
printf("輸入新圖片的高度: ");
scanf("%d",&new_Height);
printf("新圖片尺寸:w=%d h=%d\r\n",new_Width,new_Height);
/*4. 申請(qǐng)存放圖片數(shù)據(jù)的空間*/
src_buff=malloc(src_info.biWidth*src_info.biHeight*3);
new_buff=malloc(new_Width*new_Height*3);
if(new_buff==NULL||src_buff==NULL)
{
printf("malloc申請(qǐng)空間失敗!\r\n");
return -1;
}
/*5. 讀取源圖片RGB數(shù)據(jù)*/
fseek(src_file,src_head.bfOffBits,SEEK_SET); //移動(dòng)文件指針到RGB數(shù)據(jù)位置
fread(src_buff,1,src_info.biWidth*src_info.biHeight*3,src_file); //讀取源數(shù)據(jù)
/*6. 縮放圖片*/
if(PicZoom(src_buff,src_info.biWidth,src_info.biHeight,new_buff,new_Width,new_Height))
{
printf("圖片縮放處理失敗!\r\n");
return -1;
}
/*7. 寫入新圖片數(shù)據(jù)*/
//填充文件頭
memset(&new_head,0,sizeof(struct BITMAPFILEHEADER));
new_head.bfType=0x4d42;
new_head.bfSize=54+new_Width*new_Height*3;
new_head.bfOffBits=54;
//填充文件參數(shù)
memset(&new_info,0,sizeof(struct BITMAPINFOHEADER));
new_info.biSize=sizeof(struct BITMAPINFOHEADER);
new_info.biWidth=new_Width;
new_info.biHeight=new_Height;
new_info.biPlanes=1;
new_info.biBitCount=24;
//寫入文件數(shù)據(jù)
fwrite(&new_head,sizeof(struct BITMAPFILEHEADER),1,new_file);
fwrite(&new_info,sizeof(struct BITMAPINFOHEADER),1,new_file);
fseek(new_file,new_head.bfOffBits,SEEK_SET); //移動(dòng)文件指針到RGB數(shù)據(jù)位置
cnt=fwrite(new_buff,1,new_info.biWidth*new_info.biHeight*3,new_file); //寫數(shù)據(jù)
/*8. 關(guān)閉圖片文件*/
fclose(new_file);
fclose(src_file);
printf("%s 新圖片創(chuàng)建成功! 路徑:程序運(yùn)行路徑下\r\n",NEW_FILE_NAME);
return 0;
}
/**********************************************************************
* 函數(shù)名稱: PicZoom
* 功能描述: 近鄰取樣插值方法縮放圖片
* 注意該函數(shù)會(huì)分配內(nèi)存來存放縮放后的圖片,用完后要用free函數(shù)釋放掉
* "近鄰取樣插值"的原理請(qǐng)參考網(wǎng)友"lantianyu520"所著的"圖像縮放算法"
* 輸入?yún)?shù): ptOriginPic - 內(nèi)含原始圖片的象素?cái)?shù)據(jù)
* ptZoomPic - 內(nèi)含縮放后的圖片的象素?cái)?shù)據(jù)
* 輸出參數(shù): 無
* 返 回 值: 0 - 成功, 其他值 - 失敗
***********************************************************************/
int PicZoom(unsigned char *ptOriginPic_aucPixelDatas,unsigned int ptOriginPic_iWidth,unsigned int ptOriginPic_iHeight,unsigned char *ptZoomPic_aucPixelDatas,unsigned int ptZoomPic_iWidth,unsigned int ptZoomPic_iHeight)
{
unsigned int ptOriginPic_iLineBytes=ptOriginPic_iWidth*3; //一行的字節(jié)數(shù)
unsigned int ptZoomPic_iLineBytes=ptZoomPic_iWidth*3; //一行的字節(jié)數(shù)
unsigned long dwDstWidth=ptZoomPic_iWidth;
unsigned long* pdwSrcXTable;
unsigned long x;
unsigned long y;
unsigned long dwSrcY;
unsigned char *pucDest;
unsigned char *pucSrc;
unsigned long dwPixelBytes=3; //像素字節(jié)
pdwSrcXTable=malloc(sizeof(unsigned long) * dwDstWidth);
if(NULL==pdwSrcXTable)
{
return -1;
}
for(x=0; x < dwDstWidth; x++)//生成表 pdwSrcXTable
{
pdwSrcXTable[x]=(x*ptOriginPic_iWidth/ptZoomPic_iWidth);
}
for(y=0; y < ptZoomPic_iHeight; y++)
{
dwSrcY=(y * ptOriginPic_iHeight/ptZoomPic_iHeight);
pucDest=ptZoomPic_aucPixelDatas + y * ptZoomPic_iLineBytes;
pucSrc=ptOriginPic_aucPixelDatas+dwSrcY * ptOriginPic_iLineBytes;
for(x=0; x ;>
2.2 BMP圖片添加水印
#include "savebmp.h"
#include "yuvtorgb.h"
/* 圖片的象素?cái)?shù)據(jù) */
typedef struct PixelDatas {
int iWidth; /* 寬度: 一行有多少個(gè)象素 */
int iHeight; /* 高度: 一列有多少個(gè)象素 */
int iBpp; /* 一個(gè)象素用多少位來表示 */
int iLineBytes; /* 一行數(shù)據(jù)有多少字節(jié) */
int iTotalBytes; /* 所有字節(jié)數(shù) */
unsigned char *VideoBuf; //存放一幀攝像頭的數(shù)據(jù)
//指向了存放攝像頭數(shù)據(jù)的空間地址
}T_PixelDatas;
T_PixelDatas Pixedata; //存放實(shí)際的圖像數(shù)據(jù)
/*
USB攝像頭相關(guān)參數(shù)定義
*/
struct v4l2_buffer tV4l2Buf;
int iFd;
int ListNum;
unsigned char* pucVideBuf[4]; // 視頻BUFF空間地址
void camera_pthread(void);
int main(int argc ,char *argv[])
{
if(argc!=2)
{
printf("./app /dev/videoX\n");
return -1;
}
camera_init(argv[1]); //攝像頭設(shè)備初始化
//開始采集攝像頭數(shù)據(jù),并編碼保存為BMP圖片
camera_pthread();
return 0;
}
//攝像頭設(shè)備的初始化
int camera_init(char *video)
{
int i=0;
int cnt=0;
//定義攝像頭驅(qū)動(dòng)的BUF的功能捕獲視頻
int iType = V4L2_BUF_TYPE_VIDEO_CAPTURE;
/* 1、打開視頻設(shè)備 */
iFd = open(video,O_RDWR);
if(iFd < 0)
{
printf("攝像頭設(shè)備打開失敗!\n");
return 0;
}
struct v4l2_format tV4l2Fmt;
/* 2、 VIDIOC_S_FMT 設(shè)置攝像頭使用哪種格式 */
memset(&tV4l2Fmt, 0, sizeof(struct v4l2_format));
tV4l2Fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //視頻捕獲
//設(shè)置攝像頭輸出的圖像格式
tV4l2Fmt.fmt.pix.pixelformat=V4L2_PIX_FMT_YUYV;
/*設(shè)置輸出的尺寸*/
tV4l2Fmt.fmt.pix.width = 640;
tV4l2Fmt.fmt.pix.height = 480;
tV4l2Fmt.fmt.pix.field = V4L2_FIELD_ANY;
//VIDIOC_S_FMT 設(shè)置攝像頭的輸出參數(shù)
ioctl(iFd, VIDIOC_S_FMT, &tV4l2Fmt);
//打印攝像頭實(shí)際的輸出參數(shù)
printf("Support Format:%d\n",tV4l2Fmt.fmt.pix.pixelformat);
printf("Support width:%d\n",tV4l2Fmt.fmt.pix.width);
printf("Support height:%d\n",tV4l2Fmt.fmt.pix.height);
/* 3、VIDIOC_REQBUFS 申請(qǐng)buffer */
/* 初始化Pixedata結(jié)構(gòu)體,為轉(zhuǎn)化做準(zhǔn)備 */
Pixedata.iBpp =24;
//高度 和寬度的賦值
Pixedata.iHeight = tV4l2Fmt.fmt.pix.height;
Pixedata.iWidth = tV4l2Fmt.fmt.pix.width;
//一行所需要的字節(jié)數(shù)
Pixedata.iLineBytes = Pixedata.iWidth*Pixedata.iBpp/8;
//一幀圖像的字節(jié)數(shù)
Pixedata.iTotalBytes = Pixedata.iLineBytes * Pixedata.iHeight;
Pixedata.VideoBuf=malloc(Pixedata.iTotalBytes); //申請(qǐng)存放圖片數(shù)據(jù)空間
//v412請(qǐng)求命令
struct v4l2_requestbuffers tV4l2ReqBuffs;
memset(&tV4l2ReqBuffs, 0, sizeof(struct v4l2_requestbuffers));
/* 分配4個(gè)buffer:實(shí)際上由VIDIOC_REQBUFS獲取到的信息來決定 */
tV4l2ReqBuffs.count = 4; /*在內(nèi)核空間里開辟4個(gè)空間*/
/*支持視頻捕獲功能*/
tV4l2ReqBuffs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
/* 表示申請(qǐng)的緩沖是支持MMAP(內(nèi)存映射) */
tV4l2ReqBuffs.memory = V4L2_MEMORY_MMAP;
/* 為分配buffer做準(zhǔn)備 */
ioctl(iFd, VIDIOC_REQBUFS, &tV4l2ReqBuffs);
for (i = 0; i < tV4l2ReqBuffs.count; i++)
{
memset(&tV4l2Buf, 0, sizeof(struct v4l2_buffer));
tV4l2Buf.index = i; // 0 1 2 3
tV4l2Buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /*支持視頻捕獲*/
tV4l2Buf.memory = V4L2_MEMORY_MMAP; /*支持內(nèi)存映射*/
/* 6、VIDIOC_QUERYBUF 確定每一個(gè)buffer的信息 并且 mmap */
ioctl(iFd, VIDIOC_QUERYBUF, &tV4l2Buf);
//映射空間地址
pucVideBuf[i] = mmap( /*返回用戶空間的地址*/
0, /*表示系統(tǒng)自己制定地址*/
tV4l2Buf.length, /*映射的長(zhǎng)度*/
PROT_READ, /*空間數(shù)據(jù)只讀*/
MAP_SHARED, /*空間支持共享*/
iFd, /*將要映射的文件描述符*/
tV4l2Buf.m.offset /*從哪個(gè)位置開始映射,表示起始位置*/
);
printf("mmap %d addr:%p\n",i,pucVideBuf[i]);
}
/* 4、VIDIOC_QBUF 放入隊(duì)列*/
for (i = 0; i 在LCD上顯示:rgb888 */
initLut();
printf("開始采集數(shù)據(jù).......\n");
// while(1)
// {
FD_ZERO(&readfds);
FD_SET(iFd,&readfds);
select(iFd+1,&readfds,NULL,NULL,NULL); /*檢測(cè)文件描述符是否發(fā)生了讀寫事件*/
memset(&tV4l2Buf, 0, sizeof(struct v4l2_buffer));
tV4l2Buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //類型
tV4l2Buf.memory = V4L2_MEMORY_MMAP; //存儲(chǔ)空間類型
/* 9、VIDIOC_DQBUF 從隊(duì)列中取出 */
error = ioctl(iFd, VIDIOC_DQBUF, &tV4l2Buf); //取出一幀數(shù)據(jù)
ListNum = tV4l2Buf.index; //索引編號(hào) 0
//將YUV轉(zhuǎn)換為RGB
Pyuv422torgb32(pucVideBuf[ListNum],Pixedata.iWidth,Pixedata.iHeight,Pixedata.VideoBuf);
//保存BMP
save_bmp(Pixedata.VideoBuf,Pixedata.iWidth,Pixedata.iHeight);
memset(&tV4l2Buf, 0, sizeof(struct v4l2_buffer));
tV4l2Buf.index = ListNum;
tV4l2Buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
tV4l2Buf.memory = V4L2_MEMORY_MMAP;
error = ioctl(iFd, VIDIOC_QBUF, &tV4l2Buf); /*將緩沖區(qū)再次放入隊(duì)列*/
// }
};>
-
攝像頭
+關(guān)注
關(guān)注
59文章
4793瀏覽量
95275 -
BMP
+關(guān)注
關(guān)注
0文章
48瀏覽量
17027
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論