C++—— 讀入一張bmp圖片,提取其影象資料,存入矩陣/txt檔案
阿新 • • 發佈:2018-12-10
本文章完成的是讀入bmp圖片、將資料存入矩陣/TXT檔案、儲存圖片的功能。
在開始之前,我們需要了解bmp點陣圖的儲存方式:
BMP檔案的資料按照從檔案頭開始的先後順序分為四個部分:(1)bmp檔案頭(bmp file header):提供檔案的格式、大小等資訊(2)點陣圖資訊頭(bitmap information):提供影象資料的尺寸、位平面數、壓縮方式、顏色索引等資訊(3)調色盤(color palette):可選,如使用索引來表示影象,調色盤就是索引與其對應的顏色的對映表
(4)點陣圖資料(bitmap data):影象資料,畫素按照從下到上、從左到右的順序每行佔用的空間必須是4的整數倍
read_save.h
- #include<fstream>
- #include<windows.h>
- #include<iostream>
- using namespace std;
- unsigned char *pBmpBuf;//讀入影象資料的指標
- int bmpWidth;//影象的寬
- int bmpHeight;//影象的高
- RGBQUAD *pColorTable;//顏色表指標
- int biBitCount;//影象型別,每畫素位數
- //顯示點陣圖檔案頭資訊
- void showBmpHead(BITMAPFILEHEADER pBmpHead){
- cout << "\n點陣圖檔案頭:" << endl
; - cout << "檔案大小:" << pBmpHead.bfSize << endl;
- cout << "保留字_1:" << pBmpHead.bfReserved1 << endl;
- cout << "保留字_2:" << pBmpHead.bfReserved2 << endl;
- cout << "實際點陣圖資料的偏移位元組數:" << pBmpHead.bfOffBits << endl << endl;
- }
- //顯示點陣圖資訊頭資訊
- void showBmpInforHead(BITMAPINFOHEADER pBmpInforHead){
- cout << "\n點陣圖資訊頭:" << endl;
- cout << "結構體的長度:" << pBmpInforHead.biSize << endl;
- cout << "點陣圖寬:" << pBmpInforHead.biWidth << endl;
- cout << "點陣圖高:" << pBmpInforHead.biHeight << endl;
- cout << "biPlanes平面數:" << pBmpInforHead.biPlanes << endl;
- cout << "biBitCount採用顏色位數:" << pBmpInforHead.biBitCount << endl;
- cout << "壓縮方式:" << pBmpInforHead.biCompression << endl;
- cout << "biSizeImage實際點陣圖資料佔用的位元組數:" << pBmpInforHead.biSizeImage << endl;
- cout << "X方向解析度:" << pBmpInforHead.biXPelsPerMeter << endl;
- cout << "Y方向解析度:" << pBmpInforHead.biYPelsPerMeter << endl;
- cout << "使用的顏色數:" << pBmpInforHead.biClrUsed << endl;
- cout << "重要顏色數:" << pBmpInforHead.biClrImportant << endl;
- }
- //-----------------------------------------------------------------------------------------
- //給定一個影象點陣圖資料、寬、高、顏色表指標及每畫素所佔的位數等資訊,將其寫到指定檔案中
- bool readBmp(char *bmpName)
- {
- FILE *fp = fopen(bmpName, "rb");//二進位制讀方式開啟指定的影象檔案
- if (fp == 0)
- return 0;
- //跳過點陣圖檔案頭結構BITMAPFILEHEADER
- fseek(fp, sizeof(BITMAPFILEHEADER), 0);
- /*
- BITMAPFILEHEADER filehead;
- fread(&filehead, 1, sizeof(BITMAPFILEHEADER), fp);
- showBmpHead(filehead);//顯示檔案頭
- */
- //定義點陣圖資訊頭結構變數,讀取點陣圖資訊頭進記憶體,存放在變數head中
- BITMAPINFOHEADER infohead;
- fread(&infohead, sizeof(BITMAPINFOHEADER), 1, fp); //獲取影象寬、高、每畫素所佔位數等資訊
- bmpWidth = infohead.biWidth;
- bmpHeight = infohead.biHeight;
- biBitCount = infohead.biBitCount;//定義變數,計算影象每行畫素所佔的位元組數(必須是4的倍數)
- showBmpInforHead(infohead);//顯示資訊頭
- int lineByte = (bmpWidth * biBitCount / 8 + 3) / 4 * 4;//灰度影象有顏色表,且顏色表表項為256
- if (biBitCount == 8)
- {
- //申請顏色表所需要的空間,讀顏色表進記憶體
- pColorTable = new RGBQUAD[256];
- fread(pColorTable, sizeof(RGBQUAD), 256, fp);
- }
- //申請點陣圖資料所需要的空間,讀點陣圖資料進記憶體
- pBmpBuf = new unsigned char[lineByte * bmpHeight];
- fread(pBmpBuf, 1, lineByte * bmpHeight, fp);
- fclose(fp);//關閉檔案
- return 1;//讀取檔案成功
- }
- //儲存圖片
- bool saveBmp(char *bmpName, unsigned char *imgBuf, int width, int height, int biBitCount, RGBQUAD *pColorTable)
- {
- //如果點陣圖資料指標為0,則沒有資料傳入,函式返回
- if (!imgBuf)
- return 0;
- //顏色表大小,以位元組為單位,灰度影象顏色表為1024位元組,彩色影象顏色表大小為0
- int colorTablesize = 0;
- if (biBitCount == 8)
- colorTablesize = 1024;
- //待儲存影象資料每行位元組數為4的倍數
- int lineByte = (width * biBitCount / 8 + 3) / 4 * 4;
- //以二進位制寫的方式開啟檔案
- FILE *fp = fopen(bmpName, "wb");
- if (fp == 0)
- return 0;
- //------------------------------------------------------------------------------------------------------------------
- //申請點陣圖檔案頭結構變數,填寫檔案頭資訊
- BITMAPFILEHEADER fileHead;
- fileHead.bfType = 0x4D42;//bmp型別
- //bfSize是影象檔案4個組成部分之和
- fileHead.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + colorTablesize + lineByte*height;
- fileHead.bfReserved1 = 0;
- fileHead.bfReserved2 = 0;
- //bfOffBits是影象檔案前3個部分所需空間之和
- fileHead.bfOffBits = 54 + colorTablesize;
- //--------------------------------------------------------------------------------------------------------------------
- //寫檔案頭進檔案
- fwrite(&fileHead, sizeof(BITMAPFILEHEADER), 1, fp);
- //申請點陣圖資訊頭結構變數,填寫資訊頭資訊
- BITMAPINFOHEADER infohead;
- infohead.biBitCount = biBitCount;
- infohead.biClrImportant = 0;
- infohead.biClrUsed = 0;
- infohead.biCompression = 0;
- infohead.biHeight = height;
- infohead.biPlanes = 1;
- infohead.biSize = 40;
- infohead.biSizeImage = lineByte*height;
- infohead.biWidth = width;
- infohead.biXPelsPerMeter = 0;
- infohead.biYPelsPerMeter = 0;
- //寫點陣圖資訊頭進記憶體
- fwrite(&infohead, sizeof(BITMAPINFOHEADER), 1, fp);
- //----------------------------------------------------------------------------------------------------------------------
- //如果灰度影象,有顏色表,寫入檔案
- if (biBitCount == 8)
- fwrite(pColorTable, sizeof(RGBQUAD), 256, fp);
- //寫點陣圖資料進檔案
- fwrite(imgBuf, height*lineByte, 1, fp);
- //關閉檔案
- fclose(fp);
- return 1;
- }
read.cpp
- #include<cstdlib>
- #include<cstdio>
- #include<cmath>
- #include<iomanip>
- #include"readbmp.h"
- #include"savebmp.h"
- using namespace std;
- //unsigned int out_r[2000][2000];
- //unsigned int out_g[2000][2000];
- //unsigned int out_b[2000][2000];
- unsigned int **out_r;
- unsigned int **out_g;
- unsigned int **out_b;
- void doIt()
- {
- char readPath[] = "D:\\C++_file\\image_deal_C++\\read_BMP\\lunpan.bmp";
- readBmp(readPath);
- // 輸出整體影象資訊
- cout << "\nwidth=" << bmpWidth << "\nheight=" << bmpHeight << "\nbiBitCount=" << biBitCount << endl;
- // 影象的位元組數
- int linebyte1 = (bmpWidth*biBitCount / 8 + 3) / 4 * 4;
- int n = 0, m = 0, count_xiang_su = 0;
- out_r = new unsigned int *[bmpHeight]; //開闢指標陣列
- for (int i = 0; i<bmpHeight; i++)
- out_r[i] = new unsigned int[bmpWidth];
- out_g = new unsigned int *[bmpHeight]; //開闢指標陣列
- for (int i = 0; i<bmpHeight; i++)
- out_g[i] = new unsigned int[bmpWidth];
- out_b = new unsigned int *[bmpHeight]; //開闢指標陣列
- for (int i = 0; i<bmpHeight; i++)
- out_b[i] = new unsigned int[bmpWidth];
- //初始化原始畫素的陣列。
- if (biBitCount == 8)
- {
- for (int i = 0; i<bmpHeight / 2; i++)
- {
- for (int j = 0; j<bmpWidth / 2; i++)
- *(pBmpBuf + i*linebyte1 + j) = 0;
- }
- }
- if (biBitCount == 24)
- {
- for (int i = 0; i<bmpHeight; i++)
- {
- for (int j = 0; j<bmpWidth; j++)
- {
- for (int k = 0; k<3; k++)//每畫素RGB三個分量分別置0才變成黑色
- {
- m = *(pBmpBuf + i*linebyte1 + j * 3 + k);
- count_xiang_su++;
- }
- n++;
- }
- }
- cout << "總的畫素個素為:" << n << endl;
- cout << "----------------------------------------------------" << endl;
- }
- if (biBitCount == 24)
- {
- for (int i = 0; i<bmpHeight; i++)
- {
- for (int j = 0; j<bmpWidth; j++)
- {
- out_r[bmpHeight - 1 - i][j] = pBmpBuf[j * 3 + 2 + bmpWidth*i * 3];
- out_g[bmpHeight - 1 - i][j] = pBmpBuf[j * 3 + 1 + bmpWidth *i * 3];
- out_b[bmpHeight - 1 - i][j] = pBmpBuf[j * 3 + bmpWidth *i * 3];
- }
- }
- // for (int i = 0; i<bmpHeight; i++)
- // {
- // for (int j = 0; j<bmpWidth; j++)
- // {
- // cout<<out_r[i][j]<<endl;
- // cout << out_g[i][j] << endl;
- // cout << out_b[i][j] << endl;
- // }
- // }
- }
- //---------------------------------------------------------------------------------------
- /*//將畫素資料存入TXT檔案。
- ofstream outfile;
- outfile.open("rrbmp.txt", ios::in | ios::trunc);
- if(!outfile) cout << "error" << endl;
- for (int i = 0; i<bmpHeight; i++)
- {
- for (int j = 0; j<bmpWidth; j++)
- {
- outfile << out_r[i][j] << " ";
- //cout << out_g[i][j] << endl;
- //cout << out_b[i][j] << endl;
- }
- outfile << "\n";
- }
- outfile.close();
- */
- // jiang tuxiang shuju cunpan .
- char writePath[] = "D:\\C++_file\\image_deal_C++\\read_BMP\\1.bmp";
- saveBmp(writePath, pBmpBuf, bmpWidth, bmpHeight, biBitCount, pColorTable);
- //清除緩衝區,pBmpBuf和pColorTable是全域性變數,在檔案讀入時申請的空間
- delete[]pBmpBuf;
- if (biBitCount == 8)
- delete[]pColorTable;
- }
- //
- int main()
- {
- doIt();
- system("pause");
- return 0;
- }