包含三个文件:把bmp.h、bmp.cpp、main.cpp
1.1 bmp.h
#pragma once #include#include using namespace std; typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned int DWORD; //位图文件头定义 typedef struct tagBITMAPFILEHEADER { // WORD bfType;//单独读取,结构体中就不定义了 DWORD bfSize;//文件大小 WORD bfReserved1;//保留字 WORD bfReserved2;//保留字 DWORD bfOffBits;//从文件头到实际位图数据的偏移字节数 }BITMAPFILEHEADER; //位图信息头定义 typedef struct tagBITMAPINFOHEADER { DWORD biSize;//信息头大小 DWORD biWidth;//图像宽度 DWORD biHeight;//图像高度 WORD biPlanes;//位平面数,必须为1 WORD biBitCount;//每像素位数 DWORD biCompression; //压缩类型 DWORD biSizeImage; //压缩图像大小字节数 DWORD biXPelsPerMeter; //水平分辨率 DWORD biYPelsPerMeter; //垂直分辨率 DWORD biClrUsed; //位图实际用到的色彩数 DWORD biClrImportant; //本位图中重要的色彩数 }BITMAPINFOHEADER; //位图信息头定义 //彩色图像的像素信息 typedef struct tagRgbImgData { BYTE blue; BYTE green; BYTE red; }DATA; // 灰度图像的像素信息 typedef struct tagGrayBmpData { BYTE gray; }GRAYDATA; // 调色板的结构定义,灰度图有256个调色板 typedef struct tagRGBQUAD { BYTE rgbBlue; // 蓝色的亮度(值范围为0-255) BYTE rgbGreen; // 绿色的亮度(值范围为0-255) BYTE rgbRed; // 红色的亮度(值范围为0-255) BYTE rgbReserved;// 保留,必须为0 } RGBQUAD; double xAfterRot(int x, int y, double theta, int cx, int cy); double yAfterRot(int x, int y, double theta, int cx, int cy); // 检查图片类型是不是BMP int checkImgType(const char* filename); // 彩色BMP图像读取操作 DATA* readRgbBmp(const char* filename, WORD* bfType, BITMAPFILEHEADER* strHead, BITMAPINFOHEADER* strInfo, int* h, int* mw, int* imgSize, int* cx, int* cy); // 灰色BMP图像读取操作 GRAYDATA* readGrayBmp(const char* filename, WORD* bfType, BITMAPFILEHEADER* strHead, BITMAPINFOHEADER* strInfo, RGBQUAD* ipRGB, int* h, int* mw, int* imgSize, int* cx, int* cy); int modifyWidth(int biWidth); int getImageSize(int biWidth, int biHeight, int bitCount); DATA* scale(const DATA* src, float x, float y, int mh, int mw, int imgSize, int cx, int cy, BITMAPFILEHEADER strHead, BITMAPINFOHEADER strInfo, WORD bfType); GRAYDATA* scaleGray(const GRAYDATA* src, float x, float y, int mh, int mw, int imgSize, int cx, int cy, BITMAPFILEHEADER strHead, BITMAPINFOHEADER strInfo, WORD bfType, RGBQUAD* ipRGB); DATA* rotation(const DATA* src, double theta, int mh, int mw, int imgSize, int cx, int cy, BITMAPFILEHEADER strHead, BITMAPINFOHEADER strInfo, WORD bfType); GRAYDATA* rotationGray(const GRAYDATA* src, double theta, int mh, int mw, int imgSize, int cx, int cy, BITMAPFILEHEADER strHead, BITMAPINFOHEADER strInfo,WORD bfType, RGBQUAD* ipRGB);
1. 2 bmp.cpp
#include#include #include #include #include #define PI acos(-1) #include #include #include #include "bmp.h" using namespace std; int checkImgType(const char* filename) { FILE* fpi = fopen(filename, "rb"); WORD bfType; if (fpi == NULL) { cout << filename << " 文件未能找到" << endl; return 0; } else { fread(&bfType, 1, sizeof(WORD), fpi); if (0x4d42 != bfType) { cout << "Error: The file is not a bmp image!" << endl; return 0; } } return 1; } int modifyWidth(int biWidth) { if (biWidth % 4 == 0) return biWidth; return (biWidth / 4 + 1) * 4; } int getImageSize(int biWidth, int biHeight, int bitCount) { int bytePerPixel = bitCount / 8; int LineBytes = (biWidth * bytePerPixel + 3) / 4 * 4; //这个其实也相当于是每行的宽度,但是这里的宽度指的是字节数,而不是像素数 return LineBytes * biWidth; } DATA * readRgbBmp(const char* filename, WORD * bfType, BITMAPFILEHEADER* strHead, BITMAPINFOHEADER* strInfo, int* h, int* mw, int* imgSize, int * cx, int* cy) { FILE* fpi = fopen(filename, "rb"); fread(bfType, 1, sizeof(WORD), fpi); fread(strHead, 1, sizeof(tagBITMAPFILEHEADER), fpi); fread(strInfo, 1, sizeof(tagBITMAPINFOHEADER), fpi); *h = (*strInfo).biHeight; *mw = modifyWidth((*strInfo).biWidth); *imgSize = (*h) * (*mw); *cx = (*mw) / 2; *cy = (*h) / 2; DATA* imgData = new DATA[*imgSize]; fread(imgData, 1, sizeof(DATA) * (*imgSize), fpi); return imgData; } GRAYDATA* readGrayBmp(const char* filename, WORD* bfType, BITMAPFILEHEADER* strHead, BITMAPINFOHEADER* strInfo, RGBQUAD* ipRGB, int* h, int* mw, int* imgSize, int* cx, int* cy) { FILE* fpi = fopen(filename, "rb"); fread(bfType, 1, sizeof(WORD), fpi); fread(strHead, 1, sizeof(tagBITMAPFILEHEADER), fpi); fread(strInfo, 1, sizeof(tagBITMAPINFOHEADER), fpi); fread(ipRGB, sizeof(RGBQUAD) * 256, 1, fpi); *h = (*strInfo).biHeight; *mw = modifyWidth( (*strInfo).biWidth ); *imgSize = (*h) * (*mw); *imgSize = (*h) * (*mw); *cx = (*mw) / 2; *cy = (*h) / 2; //GRAYDATA* imgData = new GRAYDATA[*imgSize]; GRAYDATA* imgData = (GRAYDATA*) malloc(sizeof(GRAYDATA) * (*imgSize)); fread(imgData, 1, sizeof(GRAYDATA) * (*imgSize), fpi); return imgData; } DATA* scale(const DATA* src, float x, float y, int mh, int mw, int imgSize, int cx, int cy, BITMAPFILEHEADER strHead, BITMAPINFOHEADER strInfo, WORD bfType) { float target_x, target_y; int int_target_x, int_target_y; DATA* target = new DATA[imgSize]; int* needItr = new int[imgSize]; memset(target, 0, sizeof(DATA) * imgSize); memset(needItr, 0, sizeof(int) * imgSize); for (int i = 0; i < mh; i++) for (int j = 0; j < mw; j++) { target_x = (j - cx) / x + cx; target_y = (i - cy) / y + cy; int_target_x = (int)target_x; int_target_y = (int)target_y; if (int_target_x - target_x < 0 || int_target_y - target_y < 0 || int_target_x <0 || int_target_x > mw || int_target_y < 0 || int_target_y > mh) { target[i * mw + j].red = 0; target[i * mw + j].green = 0; target[i * mw + j].blue = 0; needItr[i * mw + j] = 1; } else { try { target[i * mw + j].blue = src[int_target_y * mw + int_target_x].blue; target[i * mw + j].red = src[int_target_y * mw + int_target_x].red; target[i * mw + j].green = src[int_target_y * mw + int_target_x].green; } catch (...) { cout << "i: " << i << "j:" << j << endl; } } } cout << "Doing the interpolation, please wait.......(0%)" << endl; for (int i = 0; i < mh; i++) { int last = -1; for (int j = 0; j < mw; j++) { // 这里应该是找到每一行的需要插值的点 // last的值应该是每一行中需要插值的第一个点的前面一个点 if (needItr[i * mw + j] == 0) { last = j; continue; } else { // 当找到一个需要插值的点的时候 // 首先期望找到这个插值点右侧的不需要插值的第一个点 int k = j; //find next position which has value while (k < mw && needItr[i * mw + k] == 1) { k++; } if (k >= mw) { //in the last position of the line if (last == -1) break; target[i * mw + j] = target[i * mw + last]; } else { if (last == -1) { //in the first position of the line target[i * mw + j] = target[i * mw + k]; } else { //in the middle float coe = (j - last) * 1.0 / (k - last); target[i * mw + j].red = (BYTE)(((int)target[i * mw + k].red - (int)target[i * mw + last].red) * coe + (int)target[i * mw + last].red); target[i * mw + j].green = (BYTE)(((int)target[i * mw + k].green - (int)target[i * mw + last].green) * coe + (int)target[i * mw + last].green); target[i * mw + j].blue = (BYTE)(((int)target[i * mw + k].blue - (int)target[i * mw + last].blue) * coe + (int)target[i * mw + last].blue); } } } needItr[i * mw + j] = 0; } } cout << "Doing the interpolation, please wait.......(50%)" << endl; //then do the vertical interpolation for (int i = 0; i < mw; i++) { int last = -1; for (int j = 0; j < mh; j++) { if (needItr[j * mw + i] == 0) { last = j; continue; } else { int k = j; //find next position which has value while (k < mh && needItr[k * mw + i] == 1) { k++; } if (k >= mh) { //in the last position of the line if (last == -1) break; target[j * mw + i] = target[last * mw + i]; } else { if (last == -1) { //in the first position of the line target[j * mw + i] = target[k * mw + i]; } else { //in the middle float coe = (j - last) * 1.0 / (k - last); target[j * mw + i].red = (BYTE)(((int)target[k * mw + i].red - (int)target[last * mw + i].red) * coe + (int)target[last * mw + i].red); target[j * mw + i].green = (BYTE)(((int)target[k * mw + i].green - (int)target[last * mw + i].green) * coe + (int)target[last * mw + i].green); target[j * mw + i].blue = (BYTE)(((int)target[k * mw + i].blue - (int)target[last * mw + i].blue) * coe + (int)target[last * mw + i].blue); } } } needItr[j * mw + i] = 0; } } FILE* fpo1; fpo1 = fopen("scale.bmp", "wb"); BITMAPFILEHEADER newHead = strHead; BITMAPINFOHEADER newInfo = strInfo; fwrite(&bfType, 1, sizeof(WORD), fpo1); fwrite(&newHead, 1, sizeof(tagBITMAPFILEHEADER), fpo1); fwrite(&newInfo, 1, sizeof(tagBITMAPINFOHEADER), fpo1); fwrite(target, 1, sizeof(DATA) * (imgSize), fpo1); fclose(fpo1); delete[] needItr; return target; } GRAYDATA* scaleGray(const GRAYDATA* src, float x, float y, int mh, int mw, int imgSize, int cx, int cy, BITMAPFILEHEADER strHead, BITMAPINFOHEADER strInfo, WORD bfType, RGBQUAD* ipRGB) { float target_x, target_y; int int_target_x, int_target_y; GRAYDATA* target = new GRAYDATA[imgSize]; int* needItr = new int[imgSize]; memset(target, 0, sizeof(GRAYDATA) * imgSize); memset(needItr, 0, sizeof(int) * imgSize); for (int i = 0; i < mh; i++) for (int j = 0; j < mw; j++) { target_x = (j - cx) / x + cx; target_y = (i - cy) / y + cy; int_target_x = (int)target_x; int_target_y = (int)target_y; if (int_target_x - target_x < 0 || int_target_y - target_y < 0 || int_target_x <0 || int_target_x > mw || int_target_y < 0 || int_target_y > mh) { target[i * mw + j].gray = 0; needItr[i * mw + j] = 1; } else { //cout << "i: " << i << "j:" << j << endl; try { target[i * mw + j].gray = src[int_target_y * mw + int_target_x].gray; } catch (...) { //cout << "i: " << i << "j:" << j << endl; } } } cout << "Doing the interpolation, please wait.......(0%)" << endl; for (int i = 0; i < mh; i++) { int last = -1; for (int j = 0; j < mw; j++) { // 这里应该是找到每一行的需要插值的点 // last的值应该是每一行中需要插值的第一个点的前面一个点 if (needItr[i * mw + j] == 0) { last = j; continue; } else { // 当找到一个需要插值的点的时候 // 首先期望找到这个插值点右侧的不需要插值的第一个点 int k = j; //find next position which has value while (k < mw && needItr[i * mw + k] == 1) { k++; } if (k >= mw) { //in the last position of the line if (last == -1) break; target[i * mw + j] = target[i * mw + last]; } else { if (last == -1) { //in the first position of the line target[i * mw + j] = target[i * mw + k]; } else { //in the middle float coe = (j - last) * 1.0 / (k - last); target[i * mw + j].gray = (BYTE)(((int)target[i * mw + k].gray - (int)target[i * mw + last].gray) * coe + (int)target[i * mw + last].gray); } } } needItr[i * mw + j] = 0; } } cout << "Doing the interpolation, please wait.......(50%)" << endl; //then do the vertical interpolation for (int i = 0; i < mw; i++) { int last = -1; for (int j = 0; j < mh; j++) { if (needItr[j * mw + i] == 0) { last = j; continue; } else { int k = j; //find next position which has value while (k < mh && needItr[k * mw + i] == 1) { k++; } if (k >= mh) { //in the last position of the line if (last == -1) break; target[j * mw + i] = target[last * mw + i]; } else { if (last == -1) { //in the first position of the line target[j * mw + i] = target[k * mw + i]; } else { //in the middle float coe = (j - last) * 1.0 / (k - last); target[j * mw + i].gray = (BYTE)(((int)target[k * mw + i].gray - (int)target[last * mw + i].gray) * coe + (int)target[last * mw + i].gray); } } } needItr[j * mw + i] = 0; } } FILE* fpo1; fpo1 = fopen("scaleGray.bmp", "wb"); BITMAPFILEHEADER newHead = strHead; BITMAPINFOHEADER newInfo = strInfo; newHead.bfReserved1 = newHead.bfReserved2 = 0; newHead.bfOffBits = sizeof(bfType) + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD); newHead.bfSize = newHead.bfOffBits + imgSize; newInfo.biHeight = (DWORD)mh; newInfo.biWidth = (DWORD)mw; newInfo.biSizeImage = (DWORd)(imgSize); fwrite(&bfType, 1, sizeof(WORD), fpo1); fwrite(&newHead, 1, sizeof(tagBITMAPFILEHEADER), fpo1); fwrite(&newInfo, 1, sizeof(tagBITMAPINFOHEADER), fpo1); fwrite(ipRGB, sizeof(RGBQUAD), 256, fpo1); fwrite(target, 1, sizeof(GRAYDATA) * (imgSize), fpo1); fclose(fpo1); delete[] needItr; return target; } DATA * rotation(const DATA* src, double theta, int mh, int mw, int imgSize, int cx, int cy, BITMAPFILEHEADER strHead, BITMAPINFOHEADER strInfo, WORD bfType) { float target_x = 0, target_y = 0; int int_target_x, int_target_y; DATA* target = new DATA[imgSize]; int* needItr = new int[imgSize]; int* noneedItr = new int[imgSize]; memset(target, 0, sizeof(DATA) * imgSize); memset(needItr, 0, sizeof(int) * imgSize); memset(noneedItr, 0, sizeof(int) * imgSize); int count1 = 0; // 这里面越界的点很少啊 for (int i = 0; i < mh; i++) for (int j = 0; j < mw; j++) { target_x = (int)xAfterRot(j, i, theta, cx, cy); target_y = (int)yAfterRot(j, i, theta, cx, cy); int_target_x = (int)target_x; int_target_y = (int)target_y; //int_target_x - target_x < 0 || int_target_y - target_y < 0 if (int_target_x <0 || int_target_x > mw || int_target_y < 0 || int_target_y > mh) { target[i * mw + j].red = 0; target[i * mw + j].green = 0; target[i * mw + j].blue = 0; needItr[i * mw + j] = 1; count1 += 1; } else { target[i * mw + j].blue = src[int_target_y * mw + int_target_x].blue; target[i * mw + j].red = src[int_target_y * mw + int_target_x].red; target[i * mw + j].green = src[int_target_y * mw + int_target_x].green; //cout << "here rotate "< float target_x = 0, target_y = 0; int int_target_x, int_target_y; GRAYDATA* target = new GRAYDATA[imgSize]; int* needItr = new int[imgSize]; int* noneedItr = new int[imgSize]; memset(target, 0, sizeof(GRAYDATA) * imgSize); memset(needItr, 0, sizeof(int) * imgSize); memset(noneedItr, 0, sizeof(int) * imgSize); int count1 = 0; // 这里面越界的点很少啊 for (int i = 0; i < mh; i++) for (int j = 0; j < mw; j++) { target_x = (int)xAfterRot(j, i, theta, cx ,cy); target_y = (int)yAfterRot(j, i, theta, cx, cy); int_target_x = (int)target_x; int_target_y = (int)target_y; //int_target_x - target_x < 0 || int_target_y - target_y < 0 if (int_target_x <0 || int_target_x > mw || int_target_y < 0 || int_target_y > mh) { target[i * mw + j].gray = 0; needItr[i * mw + j] = 1; count1 += 1; } else { target[i * mw + j].gray = src[int_target_y * mw + int_target_x].gray; //cout << "here rotate "< x = x - cx; y = y - cy; double result = x * cos(theta) - y * sin(theta); //double result = x * cos(theta) + y * sin(theta); return result += cx; } double yAfterRot(int x, int y, double theta, int cx, int cy) { x = x - cx; y = y - cy; double result = x * sin(theta) + y * cos(theta); //double result = -x * sin(theta) + y * cos(theta); return result += cy; }
1.3 main.cpp
#include "bmp.cpp"
using namespace std;
int main() {
const char* filename1 = (char*)"D:\TestEverything\BmpCenteredManipuation\Debug\Coman.bmp"; //彩色图像
const char* filename2 = (char*)"D:\TestEverything\BmpCenteredManipuation\Debug\barbara.bmp"; //灰度图像
BITMAPFILEHEADER strHead1, strHead2;
BITMAPINFOHEADER strInfo1, strInfo2;
int h1, h2, mw1, mw2, imgSize1, imgSize2;
DATA* imgData1, *imgData3;
GRAYDATA* imgData2, *imgData4;
WORD bfType1, bfType2;
RGBQUAD* ipRGB = (RGBQUAD*)malloc(sizeof(RGBQUAD) * 256);
int cx1, cx2, cy1, cy2;
if (checkImgType(filename1)) {
imgData1 = readRgbBmp(filename1, &bfType1, &strHead1, &strInfo1, &h1, &mw1, &imgSize1, &cx1, &cy1);
float mulX, mulY;
cout << "Scale, input the x coefficient (0.1> mulX;
cout << "Scale, input the y coefficient (0.1> mulY;
imgData3 = scale(imgData1, mulX, mulY, h1, mw1, imgSize1, cx1, cy1, strHead1, strInfo1, bfType1);
double theta;
cout << "Rotation, input the angle to be rotate (0 < theta < 360): ";
cin >> theta;
theta = theta / 180 * PI;
rotation(imgData3, theta, h1, mw1, imgSize1, cx1, cy1, strHead1, strInfo1, bfType1);
}
if (checkImgType(filename2)) {
imgData2 = readGrayBmp(filename2, &bfType2, &strHead2, &strInfo2, ipRGB, &h2, &mw2, &imgSize2, &cx2, &cy2);
float mulX, mulY;
cout << "Scale, input the x coefficient (0.1> mulX;
cout << "Scale, input the y coefficient (0.1> mulY;
imgData4 = scaleGray(imgData2, mulX, mulY, h2, mw2, imgSize2, cx2, cy2, strHead2, strInfo2, bfType2, ipRGB);
const char* filename4 = (char*)"D:TestEverythingBmpCenteredManipuationBmpCenteredManipuationscaleGray.bmp"; //彩色图像
double theta;
cout << "Rotation, input the angle to be rotate (0 < theta < 360): ";
cin >> theta;
theta = theta / 180 * PI;
rotationGray(imgData4, theta, h2, mw2, imgSize2, cx2, cy2, strHead2, strInfo2, bfType2, ipRGB);
}
return 0;
}
2 实现效果
- 1 灰度图
2.2 彩色图
BMP的存储结构;转化时的矩阵变换操作



