// img_rotate.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#pragma pack(1)
typedef struct tagBITMAPFILEHEADER {
int16_t bfType;//指定文件类型,必须是"BM"
int32_t bfSize;//指定文件的大小,以字节表示
int16_t bfReserved1;//保留字,必须为0
int16_t bfReserved2;//保留字,必须为0
int32_t bfOffBits; //指定从实际图像数据到文件头起始的偏移量,以字节为单位
} BITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER {
int32_t biSize;//本结构体占用的大小,单位为字节
int32_t biWidth;//位图图像宽度,单位为像素
int32_t biHeight;
int16_t biPlanes;//设备上颜色平面数目,必须为1
int16_t biBitCount;//存储每个象素所使用的二进制位数
int32_t biCompression;//是否压缩
int32_t biSizeImage;//指定图像大小
int32_t biXPelsPerMeter;//图像的水平分辨率
int32_t biYPelsPerMeter;
int32_t biClrUsed;//实际使用的颜色数
int32_t biClrImportant;//重要颜色数
} BITMAPINFOHEADER ;
typedef struct tagRGBQUAD {
char rgbBlue;
char rgbGreen;
char rgbRed;
char rgbReserved;
} RGBQUAD;
struct point
{
//包含两个变量成员
int x;
int y;
}POINT;
#pragma pack( )
#define PI 3.1415926535
#define RADIAN(angle) ((angle)*PI/180.0)
#define MAX(a,b) (a>b)?a:b
/*
双线性插值图像旋转函数 , 旋转之后 图像不改变大小 信息有些丢失
输入参数:
img: 原图像
width:原图像的宽度
height:原图像的高度
result:旋转后的图像
sita:旋转角度(弧度制)
xr,yr : 旋转中心
BackGray:背景灰度值
*/
int TwinRotate(char* img, int width, int height, char* result, double sita, double xr, double yr, char BackGray)
{
double SinTheta = sin(sita);
double CosTheta = cos(sita);
if (result)
delete[]result;
result = new char[width * height];
// if(ResultTemp==NULL)
// return -1;
memset(result, BackGray, width * height * sizeof(char));
int x, y, px, py;
double tx, ty, p1, p2, p3, p4, p1_2, p3_4;
double ConstX = -xr * CosTheta + yr * SinTheta + xr;
double ConstY = -yr * CosTheta - xr * SinTheta + yr;
char* pRes = result, * p;
for (y = 0; y < height; y++)
{
tx = -y * SinTheta - CosTheta + ConstX;
ty = y * CosTheta - SinTheta + ConstY;
for (x = 0; x < width; x++)
{
tx += CosTheta; //x*CosTheta - y*SinTheta + ConstX; (x-xr)*CosTheta - (y-yr)*SinTheta + xr
ty += SinTheta; //y*CosTheta + x*SinTheta + ConstY; (y-yr)*CosTheta + (x-xr)*SinTheta + yr
px = (int)tx;
py = (int)ty;
if (px<0 || px>width - 2 || py<0 || py>height - 2)
{
pRes++;
continue;
}
p1 = img[py * width + px]; //此处求出周围点的值
p2 = img[py * width + px + 1];
p3 = img[(py + 1) * width + px];
p4 = img[(py + 1) * width + px + 1];
p1_2 = p1 + (tx - px) * (p2 - p1);
p3_4 = p3 + (tx - px) * (p4 - p3);
*pRes = p1_2 + (ty - py) * (p3_4 - p1_2);
pRes++;
}
}
return true;
}
void rotate_a(int srcW,int srcH,int angle,int bitCount,char* newFilePath,char * srcBuf,int lineSize){
//以图像中心为原点左上角,右上角,左下角和右下角的坐标,用于计算旋转后的图像的宽和高
point pLT, pRT, pLB, pRB;
pLT.x = -srcW / 2; pLT.y = srcH / 2;
pRT.x = srcW / 2; pRT.y = srcH / 2;
pLB.x = -srcW / 2; pLB.y = -srcH / 2;
pRB.x = srcW / 2; pRB.y = -srcH / 2;
//旋转之后的坐标
point pLTN, pRTN, pLBN, pRBN;
double sina = sin(RADIAN(angle));
double cosa = cos(RADIAN(angle));
pLTN.x = pLT.x * cosa + pLT.y * sina;
pLTN.y = -pLT.x * sina + pLT.y * cosa;
pRTN.x = pRT.x * cosa + pRT.y * sina;
pRTN.y = -pRT.x * sina + pRT.y * cosa;
pLBN.x = pLB.x * cosa + pLB.y * sina;
pLBN.y = -pLB.x * sina + pLB.y * cosa;
pRBN.x = pRB.x * cosa + pRB.y * sina;
pRBN.y = -pRB.x * sina + pRB.y * cosa;
//旋转后图像宽和高
int desWidth = MAX(abs(pRBN.x - pLTN.x), abs(pRTN.x - pLBN.x));
int desHeight = MAX(abs(pRBN.y - pLTN.y), abs(pRTN.y - pLBN.y));
//分配旋转后图像的缓存
int desBufSize = ((desWidth * bitCount + 31) / 32) * 4 * desHeight;
printf("desWidth=%d desHeight=%d (desWidth*bitCount+31)/32)*4 =%d \r\n", desWidth, desHeight, ((desWidth * bitCount + 31) / 32) * 4);
char* desBuf = (char*)malloc(desBufSize);
//将所有像素都预置为白色
memset(desBuf, 0xff, desBufSize);
//新图像每一行字节数,带有偏移量
int desLineSize = ((desWidth * bitCount + 31) / 32) * 4;
//通过新图像的坐标,计算对应的原图像的坐标
printf("srcW=%d lineSize=%d \r\n", srcW, lineSize);
int i = 0,j=0;
for (i = 0; i < desHeight; i++)
{
for (j = 0; j < desWidth; j++)
{
//转换到以图像为中心的坐标系,并进行逆旋转
//x1 = rcos(b-a) = rcosbcosa+rsinbsina=x0cosa+y0sina;
//y1 = rsin(b - a) = rsinbcosa - rcosbsina = -x0sina + y0cosa;int x = i * c + j * s + di;
/*
int x = i * c + j * s + di;
int y = j * c - i * s + dj;
int dstOft = (x * width + y) * 3;
int srcOft = (i * srcH + j) * 3;
*/
int tX = (j - desWidth / 2) * cos(RADIAN(360 - angle)) + (-i + desHeight / 2) * sin(RADIAN(360 - angle));
int tY = -(j - desWidth / 2) * sin(RADIAN(360 - angle)) + (-i + desHeight / 2) * cos(RADIAN(360 - angle));
//如果这个坐标不在原图像内,则不赋值
if (tX > srcW / 2 || tX < -srcW / 2 || tY > srcH / 2 || tY < -srcH / 2)
{
continue;
}
//再转换到原坐标系下
int tXN = tX + srcW / 2;
int tYN = abs(tY - srcH / 2);
//值拷贝
memcpy(&desBuf[i * desLineSize + j * bitCount / 8], &srcBuf[tYN * lineSize + tXN * bitCount / 8], bitCount/8);
/* desBuf[i * desLineSize + j * bitCount / 8 + 0] = srcBuf[tYN * srcW * bitCount / 8 + tXN * bitCount / 8 + 0];
desBuf[i * desLineSize + j * bitCount / 8 + 1] = srcBuf[tYN * srcW * bitCount / 8 + tXN * bitCount / 8 + 1];
desBuf[i * desLineSize + j * bitCount / 8 + 2] = srcBuf[tYN * srcW * bitCount / 8 + tXN * bitCount / 8 + 2];
*/
}
}
//文件头信息
BITMAPFILEHEADER nbmfHeader;
nbmfHeader.bfType = 0x4D42;
nbmfHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + desWidth * desHeight * bitCount / 8;
nbmfHeader.bfReserved1 = 0;
nbmfHeader.bfReserved2 = 0;
nbmfHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
//Bitmap头信息
BITMAPINFOHEADER bmi;
bmi.biSize = sizeof(BITMAPINFOHEADER);
bmi.biWidth = desWidth;
bmi.biHeight = desHeight;
bmi.biPlanes = 1;
bmi.biBitCount = bitCount;
bmi.biCompression = 0;
bmi.biSizeImage = 0;
bmi.biXPelsPerMeter = 0;
bmi.biYPelsPerMeter = 0;
bmi.biClrUsed = 0;
bmi.biClrImportant = 0;
char* newimg = (char*)calloc(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + desBufSize, sizeof(char));
if (newimg) {
memcpy(newimg, &nbmfHeader, sizeof(BITMAPFILEHEADER));
memcpy(newimg + sizeof(BITMAPFILEHEADER), &bmi, sizeof(BITMAPINFOHEADER));
memcpy(newimg + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER), desBuf, desBufSize);
FILE* newfp = NULL;
fopen_s(&newfp, newFilePath, "w+");
for (i = 0; i < sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + desBufSize; i++)
{
fputc((uint8_t)newimg[i], newfp);
}
fclose(newfp);
}
}
void rotate_b(int srcW, int srcH, int bitCount, int angle, int lineSize, char* srcBuf, char* newFilePath) {
double theta = angle * 3.141592 / 180.0;
float c = cos(theta);
float s = sin(theta);
/* 计算中点坐标 */
int h = (srcW + 1) / 2;
int w = (srcH + 1) / 2;
/* 计算矩形4个顶点旋转后对应的坐标 */
float x0 = -w * c - h * s;
float y0 = -h * c + w * s;
float x1 = w * c - h * s;
float y1 = -h * c - w * s;
float x2 = w * c + h * s;
float y2 = h * c - w * s;
float x3 = -w * c + h * s;
float y3 = h * c + w * s;
/* 计算旋转后的图像的高度和宽度 */
float width1 = fabs(x2 - x0);
float width2 = fabs(x3 - x1);
float height1 = fabs(y2 - y0);
float height2 = fabs(y3 - y1);
int width = (width1 > width2 ? width1 : width2);
int height = (height1 > height2 ? height1 : height2);
/* 创建图像数据缓冲区 */
int desWidth = height;
int desHeight = width;
// dst.Create(dst.rows, dst.cols, 3);
int desBufSize = ((desWidth * bitCount + 31) / 32) * 4 * desHeight;
printf("desWidth=%d desHeight=%d (desWidth*bitCount+31)/32)*4 =%d \r\n", desWidth, desHeight, ((desWidth * bitCount + 31) / 32) * 4);
char* desBuf = (char*)malloc(desBufSize);
//将所有像素都预置为白色
memset(desBuf, 0xff, desBufSize);
//新图像每一行字节数,带有偏移量
int desLineSize = ((desWidth * bitCount + 31) / 32) * 4;
printf("desLineSize=%d\r\n", desLineSize);
char* destbuf = (char*)malloc(desWidth * desHeight * bitCount / 8);
/* 计算原始像素坐标对应的目标坐标 */
int di = x0 + width / 2;
int dj = y0 + height / 2;
for (int i = 0; i < srcW; i++)
{
for (int j = 0; j < srcH; j++)
{
int x = i * c + j * s + di;
int y = j * c - i * s + dj;
int dstOft = (x * width + y) * 3;
int srcOft = (i * srcH + j) * 3;
//memcpy(&desBuf[x * desLineSize + y * bitCount / 8], &srcBuf[(i * srcW + j )* bitCount / 8], bitCount / 8);
//memcpy(&desBuf[i * desLineSize + j * bitCount / 8], &srcBuf[srcOft], bitCount / 8);
destbuf[dstOft + 0] = srcBuf[srcOft + 0]; // B
destbuf[dstOft + 1] = srcBuf[srcOft + 1]; // G
destbuf[dstOft + 2] = srcBuf[srcOft + 2]; // R
}
}
printf("desLineSize=%d desWidth* bitCount/8=%d \r\n", desLineSize, desWidth * bitCount / 8);
for (size_t i = 0; i < desHeight; i++)
{
memcpy(&desBuf[i * desLineSize], &destbuf[i * desWidth * bitCount / 8], desWidth * bitCount / 8);
}
//文件头信息
BITMAPFILEHEADER nbmfHeader;
nbmfHeader.bfType = 0x4D42;
nbmfHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + desWidth * desHeight * bitCount / 8;
nbmfHeader.bfReserved1 = 0;
nbmfHeader.bfReserved2 = 0;
nbmfHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
//Bitmap头信息
BITMAPINFOHEADER bmi;
bmi.biSize = sizeof(BITMAPINFOHEADER);
bmi.biWidth = desWidth;
bmi.biHeight = desHeight;
bmi.biPlanes = 1;
bmi.biBitCount = bitCount;
bmi.biCompression = 0;
bmi.biSizeImage = 0;
bmi.biXPelsPerMeter = 0;
bmi.biYPelsPerMeter = 0;
bmi.biClrUsed = 0;
bmi.biClrImportant = 0;
char* newimg = (char*)calloc(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + desBufSize, sizeof(char));
if (newimg) {
memcpy(newimg, &nbmfHeader, sizeof(BITMAPFILEHEADER));
memcpy(newimg + sizeof(BITMAPFILEHEADER), &bmi, sizeof(BITMAPINFOHEADER));
memcpy(newimg + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER), desBuf, desBufSize);
FILE* newfp = NULL;
fopen_s(&newfp, newFilePath, "w+");
size_t i = 0;
for (i = 0; i < sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + desBufSize; i++)
{
fputc((uint8_t)newimg[i], newfp);
}
fclose(newfp);
}
}
void rotate_c(int srcW,int srcH, int bitCount, int angle,int lineSize,char* srcBuf,char* newFilePath) {
double theta = angle * 3.1415926535 / 180.0;
float c = cos(theta);
float s = sin(theta);
/* 计算中点坐标 */
int h = (srcW + 1) / 2;
int w = (srcH + 1) / 2;
/* 计算矩形4个顶点旋转后对应的坐标 */
float x0 = -w * c - h * s;
float y0 = -h * c + w * s;
float x1 = w * c - h * s;
float y1 = -h * c - w * s;
float x2 = w * c + h * s;
float y2 = h * c - w * s;
float x3 = -w * c + h * s;
float y3 = h * c + w * s;
/* 计算旋转后的图像的高度和宽度 */
float width1 = fabs(x2 - x0);
float width2 = fabs(x3 - x1);
float height1 = fabs(y2 - y0);
float height2 = fabs(y3 - y1);
int width = (width1 > width2 ? width1 : width2);
int height = (height1 > height2 ? height1 : height2);
/* 创建图像数据缓冲区 */
int desWidth = height;
int desHeight = width;
// dst.Create(dst_rows, dst_cols, 3);
int desBufSize = ((desWidth * bitCount + 31) / 32) * 4 * desHeight;
printf("desWidth=%d desHeight=%d (desWidth*bitCount+31)/32)*4 =%d \r\n", desWidth, desHeight, ((desWidth * bitCount + 31) / 32) * 4);
char* desBuf = (char*)malloc(desBufSize);
//将所有像素都预置为白色
memset(desBuf, 0xff, desBufSize);
//新图像每一行字节数,带有偏移量
int desLineSize = ((desWidth * bitCount + 31) / 32) * 4;
printf("desLineSize=%d\r\n", desLineSize);
char* destbuf = (char*)malloc(desWidth* desHeight* bitCount/8);
//通过新图像的坐标,计算对应的原图像的坐标
/* 计算目标像素坐标对应的原始图像的坐标 */
c = cos(-theta);
s = sin(-theta);
h = (desWidth + 1) / 2;
w = (desHeight + 1) / 2;
int di = -w * c - h * s + srcH / 2;
int dj = -h * c + w * s + srcW / 2;
for (int i = 0; i < desWidth; i++)
{
for (int j = 0; j < desHeight; j++)
{
int x = i * c + j * s + di;
int y = j * c - i * s + dj;
if (x >= srcW || y >= srcH || x < 0 || y < 0) continue; // 越界检查
int srcOft = (x * srcH + y) * 3;
int dstOft = (i * width + j) * 3;
destbuf[dstOft + 0] = srcBuf[srcOft + 0]; // B
destbuf[dstOft + 1] = srcBuf[srcOft + 1]; // G
destbuf[dstOft + 2] = srcBuf[srcOft + 2]; // R
//memcpy(&desBuf[i* desLineSize + j * bitCount / 8], &srcBuf[(x * srcH + y) * bitCount / 8], bitCount / 8);
}
}
printf("desLineSize=%d desWidth* bitCount/8=%d \r\n", desLineSize, desWidth * bitCount / 8);
for (size_t i = 0; i < desHeight; i++)
{
memcpy(&desBuf[i*desLineSize], &destbuf[i* desWidth* bitCount / 8], desWidth* bitCount / 8);
}
//文件头信息
BITMAPFILEHEADER nbmfHeader;
nbmfHeader.bfType = 0x4D42;
nbmfHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + desWidth * desHeight * bitCount / 8;
nbmfHeader.bfReserved1 = 0;
nbmfHeader.bfReserved2 = 0;
nbmfHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
//Bitmap头信息
BITMAPINFOHEADER bmi;
bmi.biSize = sizeof(BITMAPINFOHEADER);
bmi.biWidth = desWidth;
bmi.biHeight = desHeight;
bmi.biPlanes = 1;
bmi.biBitCount = bitCount;
bmi.biCompression = 0;
bmi.biSizeImage = 0;
bmi.biXPelsPerMeter = 0;
bmi.biYPelsPerMeter = 0;
bmi.biClrUsed = 0;
bmi.biClrImportant = 0;
char* newimg = (char*)calloc(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + desBufSize, sizeof(char));
if (newimg) {
memcpy(newimg, &nbmfHeader, sizeof(BITMAPFILEHEADER));
memcpy(newimg + sizeof(BITMAPFILEHEADER), &bmi, sizeof(BITMAPINFOHEADER));
memcpy(newimg + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER), desBuf, desBufSize);
FILE* newfp = NULL;
fopen_s(&newfp, newFilePath, "w+");
size_t i = 0;
for (i = 0; i < sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + desBufSize; i++)
{
fputc((uint8_t)newimg[i], newfp);
}
fclose(newfp);
}
}
//https://blog.csdn.net/iteye_11687/article/details/82073391
int main()
{
std::cout << "Hello World!\n";
const char* charFilePath = "C:\\Users\\Administrator\\Desktop\\1133.bmp";
const char* newFilePatha = "C:\\Users\\Administrator\\Desktop\\11_a.bmp";
const char* newFilePathb = "C:\\Users\\Administrator\\Desktop\\11_b.bmp";
const char* newFilePathc = "C:\\Users\\Administrator\\Desktop\\11_c.bmp";
int angle =40;
FILE* pfile;
fopen_s(&pfile,charFilePath, "rb");//打开文件,返回文件操作符
char* srcRead;
size_t result;
if (pfile)//打开文件一定要判断是否成功
{
fseek(pfile, 0, SEEK_END);//将文件内部的指针指向文件末尾
long srcFileSize = ftell(pfile);//获取文件长度,(得到文件位置指针当前位置相对于文件首的偏移字节数)
rewind(pfile);//将文件内部的指针重新指向一个流的开头
srcRead = (char*)malloc(srcFileSize * sizeof(char) + 1);
if (srcRead) {
//用malloc申请的内存是没有初始值的,如果不赋值会导致写入的时候找不到结束标志符而出现内存比实际申请值大,写入数据后面跟随乱码的情况
memset(srcRead, 0, srcFileSize * sizeof(char) + 1);//将内存空间都赋值为‘\0’
result = fread(srcRead, 1, srcFileSize, pfile);//将pfile中内容读入srcRead指向内存中
BITMAPFILEHEADER* bmp_headader = (BITMAPFILEHEADER*)calloc(1, sizeof(BITMAPFILEHEADER));
memcpy(bmp_headader, srcRead, sizeof(BITMAPFILEHEADER));
int32_t bfOffBits = bmp_headader->bfOffBits;
printf("bfOffBits=%x %d\r\n",bfOffBits, sizeof(BITMAPFILEHEADER));
BITMAPINFOHEADER* bm_pinfo= (BITMAPINFOHEADER*)calloc(1, sizeof(BITMAPINFOHEADER));
memcpy(bm_pinfo, srcRead + sizeof(BITMAPFILEHEADER), sizeof(BITMAPINFOHEADER));
int srcW = bm_pinfo->biWidth;
int srcH = bm_pinfo->biHeight;
int bitCount = (bm_pinfo->biBitCount);
printf("srcW=%d srcH=%d bitCount=%d \r\n", srcW, srcH, bitCount);
int lineSize = bitCount * srcW / 8;
int alignBytes = ((srcW * bitCount + 31) & ~31) / 8L - srcW * bitCount / 8L;
//line_size = line_size % 4 == 0 ? line_size : line_size + 4 - (line_size % 4);
printf("alignBytes=%d lineSize=%d \r\n", alignBytes, lineSize);
//size_t imt_bt_sizt = srcFileSize - bfOffBits;
//char* img = (char*)calloc(1, imt_bt_sizt);
//memcpy(img, srcRead + bfOffBits, imt_bt_sizt);
int srcBufSize = lineSize * srcH;
char* srcBuf = (char*)calloc(srcBufSize, sizeof(char));
int i, j;
//读取数据
for (i = 0; i < srcH; i++)
{
memcpy(srcBuf+i* lineSize, srcRead+ bmp_headader->bfOffBits+i*(lineSize+ alignBytes), lineSize);
//printf("-->%d \r\n", srcRead + bmp_headader->bfOffBits + i * (lineSize + alignBytes));
}
printf("srcBufSize=%d\r\n", srcBufSize);
/* for ( i = 0; i < srcBufSize; i++)
{
printf("%02x ",(uint8_t)srcBuf[i]);
if (0 != i && 0 == i % lineSize) {
printf("\r\n");
}
}*/
rotate_a(srcW, srcH, angle, bitCount, (char*)newFilePatha,srcBuf,lineSize);
//rotate_b(srcW, srcH, bitCount, angle, lineSize, srcBuf, (char*)newFilePathb);
//rotate_c(srcW,srcH, bitCount,angle, lineSize,srcBuf,(char*)newFilePathc);
}
//QString qstr = QString::fromLocal8Bit(srcRead);//要进行转码,否则中文字符无法显示
fclose(pfile);//关掉文件操作符,和句柄一样,有open就一定有close
free(srcRead);//释放内存
}
srcRead = NULL;//指针不再使用,一定要“删除”,防止产生野指针
}
// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单
// 入门使用技巧:
// 1. 使用解决方案资源管理器窗口添加/管理文件
// 2. 使用团队资源管理器窗口连接到源代码管理
// 3. 使用输出窗口查看生成输出和其他消息
// 4. 使用错误列表窗口查看错误
// 5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
// 6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件