1. 程式人生 > >BMP影象旋轉----C++實現

BMP影象旋轉----C++實現

如果前面幾個實驗都做過了的,做這個應該很簡單,今天也是看到影象相關的文章,所以也就複習了一遍,以前也就是知道原理,沒編過,這次就都完成了吧。。下面我做的是一個BMP影象旋轉的實驗。(我選的是180,相對來說比較簡單)。

我的程式碼:

#include<iostream>
#include <Windows.h>

using namespace std;


void main()
{
	
	FILE* stream=fopen("D:\\3.bmp","rb");
	if(stream==NULL)
	{
		cout<<"檔案不存在"<<endl;
		return;
	}
	
	int sizeFileHeader=sizeof(BITMAPFILEHEADER);
	int sizeInfoHeader=sizeof(BITMAPINFOHEADER);
	
	BITMAPFILEHEADER* bitmapFileHeader=new BITMAPFILEHEADER[sizeFileHeader+1];
	
	BITMAPINFOHEADER* bitmapInfoHeader=new BITMAPINFOHEADER[sizeInfoHeader+1];
	
	memset(bitmapFileHeader,0,sizeFileHeader+1);
	memset(bitmapInfoHeader,0,sizeInfoHeader+1);
	fread(bitmapFileHeader,sizeof(char),sizeFileHeader,stream);
	fseek(stream,sizeFileHeader,0);
	fread(bitmapInfoHeader,sizeof(char),sizeInfoHeader,stream);
	int srcImageLineByteCount=(((bitmapInfoHeader->biWidth*24)+31)/32)*4;
	fseek(stream,sizeFileHeader+sizeInfoHeader,0);

	//讀取影象資料
	int count=srcImageLineByteCount-bitmapInfoHeader->biWidth*(bitmapInfoHeader->biBitCount/8);
	BYTE* tempData=new BYTE[count];
	BYTE*** oldImageData=new BYTE**[bitmapInfoHeader->biHeight];
	for(int i=0;i<bitmapInfoHeader->biHeight;i++)
	{
		oldImageData[i]=new BYTE*[bitmapInfoHeader->biWidth];
		for (int j=0;j<bitmapInfoHeader->biWidth;j++)
		{
			oldImageData[i][j]=new BYTE[3];
			for(int k=0;k<3;k++)
			{
				fread(&oldImageData[i][j][k],sizeof(BYTE),1,stream);
			}
		}
		
		for(int m=0;m<count;m++)
		{
			fread(&tempData[m],sizeof(BYTE),1,stream);
		}
	}
	

	fclose(stream);
	
	//得到資料
	
	BYTE*** newImageData=new BYTE**[bitmapInfoHeader->biHeight];
	
	for(int i=0;i<bitmapInfoHeader->biHeight;i++)
	{
		newImageData[i]=new BYTE*[bitmapInfoHeader->biWidth];
		for (int j=0;j<bitmapInfoHeader->biWidth;j++)
		{
			newImageData[i][j]=new BYTE[3];
			for (int k=0;k<3;k++)
			{
				newImageData[i][j][k]=oldImageData[bitmapInfoHeader->biHeight-i-1][bitmapInfoHeader->biWidth-j-1][k];
			}
		}
		
	}


	//寫資料
	FILE* fileWrite=fopen("D:\\7.bmp","a+");
	fwrite(bitmapFileHeader,sizeof(char),sizeof(BITMAPFILEHEADER),fileWrite);
	fwrite(bitmapInfoHeader,sizeof(char),sizeof(BITMAPINFOHEADER),fileWrite);
	for(int i=0;i<bitmapInfoHeader->biHeight;i++)
	{
		for(int j=0;j<bitmapInfoHeader->biWidth;j++)
		{
			for(int k=0;k<3;k++)
			{
				fwrite(&newImageData[i][j][k],sizeof(BYTE),1,fileWrite);
			}
			
		}
		for (int s=0;s<count;s++)
		{
			fwrite(&tempData[s],sizeof(BYTE),1,fileWrite);
		}

	}
	fclose(fileWrite);
	delete newImageData;
	delete oldImageData;

	cout<<"success"<<endl;
}

程式碼分析:其實這裡有個很關鍵的問題:那就是記憶體對齊的那段記憶體,我們在讀取資料的時候,必須把它刪除,但是在我們向檔案裡寫資料的時候,我們必須把它給補上,因為那些補齊的記憶體資料就是00 00 00所以我就用了一個數組把它存起來(其實在讀取檔案的時候,我是通過讀取的方式填充這個陣列,而不是直接給它賦值,大家從程式碼中可以看出來。。我在這裡只是強調一下)。

int count=srcImageLineByteCount-bitmapInfoHeader->biWidth*(bitmapInfoHeader->biBitCount/8);
BYTE* tempData=new BYTE[count];

這裡的count是指那段補齊的記憶體位元組多少,這裡我測試的是3,(我的寬度是407,24位)。

不懂為什麼這樣寫的參看前面幾章的內容,也可以留言。。

再說一下我儲存資料的那個三維指標(也不知道是不是這樣稱呼的,暫且這樣說吧,大家都懂的。。)

BYTE*** oldImageData=new BYTE**[bitmapInfoHeader->biHeight];

BYTE*** newImageData=new BYTE**[bitmapInfoHeader->biHeight];

我的思路是:所有的資料=高度*寬度*畫素所佔位元組數。我的是:407*360*3。我逐行遍歷,再逐畫素(畫素間)遍歷,然後在畫素的內部遍歷。

好了,這個程式就OK了。。。睡覺。。。悲劇的一天,全部花在了各種蛋疼的除錯。

我的效果:

原圖:

旋轉後的圖: