C/C++ BMP(24位真彩色)影象處理(2)------影象の擷取
阿新 • • 發佈:2019-01-06
對上一篇部落格《C/C++ BMP(24位真彩色)影象處理(1)------影象開啟與資料區處理》的程式碼做小部分的修改,就可以進行BMP影象的擷取操作,程式碼如下:
#include <string.h> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <malloc.h> #include<time.h>//時間相關標頭檔案,可用其中函式計算影象處理速度 #define WIDTHBYTES(bits) (((bits)+31)/32*4)//用於使影象寬度所佔位元組數為4byte的倍數 #define MYCUT_HEIGHT 100 //擷取高度 #define MYCUT_WIDTH 100 //擷取寬度 #define BEGIN_X 0 //擷取點陣圖開始位置X座標 #define BEGIN_Y 0 //擷取點陣圖開始位置Y座標 typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned long DWORD; typedef long LONG; //點陣圖檔案頭資訊結構定義 //其中不包含檔案型別資訊(由於結構體的記憶體結構決定,要是加了的話將不能正確讀取檔案資訊) typedef struct tagBITMAPFILEHEADER { DWORD bfSize; //檔案大小 WORD bfReserved1; //保留字,不考慮 WORD bfReserved2; //保留字,同上 DWORD bfOffBits; //實際點陣圖資料的偏移位元組數,即前三個部分長度之和 } BITMAPFILEHEADER; //資訊頭BITMAPINFOHEADER,也是一個結構,其定義如下: typedef struct tagBITMAPINFOHEADER{ //public: DWORD biSize; //指定此結構體的長度,為40 LONG biWidth; //點陣圖寬 LONG biHeight; //點陣圖高 WORD biPlanes; //平面數,為1 WORD biBitCount; //採用顏色位數,可以是1,2,4,8,16,24,新的可以是32 DWORD biCompression; //壓縮方式,可以是0,1,2,其中0表示不壓縮 DWORD biSizeImage; //實際點陣圖資料佔用的位元組數 LONG biXPelsPerMeter; //X方向解析度 LONG biYPelsPerMeter; //Y方向解析度 DWORD biClrUsed; //使用的顏色數,如果為0,則表示預設值(2^顏色位數) DWORD biClrImportant; //重要顏色數,如果為0,則表示所有顏色都是重要的 } BITMAPINFOHEADER; void main() { long now=0; now=clock();//儲存影象處理開始時間 BITMAPFILEHEADER bitHead,writebitHead; BITMAPINFOHEADER bitInfoHead,writebitInfoHead; FILE* pfile;//輸入檔案 FILE* wfile;//輸出檔案 char strFile[50]="E:\\testpicture\\1.bmp";//開啟影象路徑,BMP影象必須為24位真彩色格式 char strFilesave[50]="E:\\testpicture\\2.bmp";//處理後圖像儲存路徑 pfile = fopen(strFile,"rb");//檔案開啟影象 wfile = fopen(strFilesave,"wb");//開啟檔案為儲存修改後影象做準備 //讀取點陣圖檔案頭資訊 WORD fileType; fread(&fileType,1,sizeof(WORD),pfile); fwrite(&fileType,1,sizeof(WORD),wfile); if(fileType != 0x4d42) { printf("file is not .bmp file!"); return; } //讀取點陣圖檔案頭資訊 fread(&bitHead,1,sizeof(tagBITMAPFILEHEADER),pfile); writebitHead=bitHead;//由於擷取影象頭和原始檔頭相似,所以先將原始檔頭資料賦予擷取檔案頭 //讀取點陣圖資訊頭資訊 fread(&bitInfoHead,1,sizeof(BITMAPINFOHEADER),pfile); writebitInfoHead=bitInfoHead;//同位圖檔案頭相似 writebitInfoHead.biHeight=MYCUT_HEIGHT;//為擷取檔案重寫點陣圖高度 writebitInfoHead.biWidth=MYCUT_WIDTH;//為擷取檔案重寫點陣圖寬度 int mywritewidth=WIDTHBYTES(writebitInfoHead.biWidth*writebitInfoHead.biBitCount);//BMP影象實際點陣圖資料區的寬度為4byte的倍數,在此計算實際資料區寬度 writebitInfoHead.biSizeImage=mywritewidth*writebitInfoHead.biHeight;//計算點陣圖實際資料區大小 writebitHead.bfSize=54+writebitInfoHead.biSizeImage;//點陣圖檔案頭大小為點陣圖資料區大小加上54byte fwrite(&writebitHead,1,sizeof(tagBITMAPFILEHEADER),wfile);//寫回點陣圖檔案頭資訊到輸出檔案 fwrite(&writebitInfoHead,1,sizeof(BITMAPINFOHEADER),wfile);//寫回點陣圖資訊頭資訊到輸出檔案 int width = bitInfoHead.biWidth; int height = bitInfoHead.biHeight; //分配記憶體空間把源圖存入記憶體 int l_width = WIDTHBYTES(width*bitInfoHead.biBitCount);//計算點陣圖的實際寬度並確保它為4byte的倍數 int write_width = WIDTHBYTES(writebitInfoHead.biWidth*writebitInfoHead.biBitCount);//計算寫點陣圖的實際寬度並確保它為4byte的倍數 BYTE *pColorData=(BYTE *)malloc(height*l_width);//開闢記憶體空間儲存影象資料 memset(pColorData,0,height*l_width); BYTE *pColorDataMid=(BYTE *)malloc(mywritewidth*MYCUT_HEIGHT);//開闢記憶體空間儲存影象處理之後資料 memset(pColorDataMid,0,mywritewidth*MYCUT_HEIGHT); long nData = height*l_width; long write_nData = mywritewidth*MYCUT_HEIGHT;//擷取的點陣圖資料區長度定義 //把點陣圖資料資訊讀到數組裡 fread(pColorData,1,nData,pfile);//影象處理可通過操作這部分資料加以實現 //擷取影象資料區操作,在操作過程中注意擷取影象是否越界,可在此處加入程式碼進行越界處理 for(int hnum=height-BEGIN_Y-MYCUT_HEIGHT;hnum<height-BEGIN_Y;hnum++)//由於BMP影象的資料儲存格式起點是影象的左下角,所以需要進行座標換算操作 for(int wnum=BEGIN_X;wnum<BEGIN_X+MYCUT_WIDTH;wnum++) { int pixel_point=hnum*l_width+wnum*3;//陣列位置偏移量,對應於影象的各畫素點RGB的起點 int write_pixel_point=(hnum-height+BEGIN_Y+MYCUT_HEIGHT)*mywritewidth+(wnum-BEGIN_X)*3; pColorDataMid[write_pixel_point]=pColorData[pixel_point]; pColorDataMid[write_pixel_point+1]=pColorData[pixel_point+1]; pColorDataMid[write_pixel_point+2]=pColorData[pixel_point+2]; } fwrite(pColorDataMid,1,write_nData,wfile); //將處理完影象資料區寫回檔案 fclose(pfile); fclose(wfile); printf("影象處理完成\n"); printf("執行時間為:%dms\n",int(((double)(clock()-now))/CLOCKS_PER_SEC*1000));//輸出影象處理花費時間資訊 }