数字图像处理学习笔记(1.1)---位图的读写、几何变换、傅里叶变换、直方图均衡

来源:互联网 发布:天猫双十一交易额数据 编辑:程序博客网 时间:2024/05/22 05:05

图像的几何变换

#include"bmp.h"#include<cmath>#include<cstring>#include<cstdio>#include<iostream>using namespace std;void Bitmap::translation(int offsetX, int offsetY)//平移变换{if (dataBuf == NULL)cout << "请确保已经读入图像数据!" << endl;int w, h;//长宽的循环变量int k;//像素通道的循环变量int pixelByte = bitCount / 8;//每像素的字节数int lineByte = (width_p*bitCount / 8 + 3) / 4 * 4;//每行像素的字节数unsigned char* transBuf = new unsigned char[height_p*lineByte];//分配数据存储空间memset(transBuf, 0, height_p*lineByte);//置为黑色//平移运算for (h = 0; h < height_p; h++){for (w = 0; w < width_p; w++){//输出的点在输入的点范围内if (h - offsetY >= 0 && h - offsetY <= height_p&&w - offsetX >= 0 && w - offsetX <= width_p){for (k = 0; k < pixelByte; k++){*(transBuf + h*lineByte + w*pixelByte + k)= *(dataBuf + (h - offsetY)*lineByte + (w - offsetX)*pixelByte + k);}}}}delete[] dataBuf;dataBuf = transBuf;//释放原数据内存,指向变换后的图像数据cout << "平移成功!" << endl;}void Bitmap::zoom(float ratioX, float ratioY, char interpolationWay = 'n')//缩放变换{switch (interpolationWay){case 'n':neighborInterpolation(ratioX, ratioX);break;case 'l':dbLinearInterpolatin(ratioX, ratioY);break;case 'c':cubicConvoInterpolatin(ratioX, ratioY);break;default:break;}}void Bitmap::neighborInterpolation(float ratioX, float ratioY){int pixelByte = bitCount / 8;//每像素字节数int widthOut = int(ratioX*width_p);//输出图像宽度和高度int heightOut = int(ratioY*height_p);int lineByte = (width_p*bitCount / 8 + 3) / 4 * 4;//原图像每行像素的字节数int lineByteOut = (widthOut*bitCount / 8 + 3) / 4 * 4;//变换后图像每行像素的字节数unsigned char* transBuf = new unsigned char[lineByteOut*heightOut];memset(transBuf, 0, lineByteOut*heightOut);int w, h;int k;//输出图像对应在输入图像中待插值的位置坐标int coordinateX, coordinateY;for (h = 0; h < heightOut; h++){for (w = 0; w < widthOut; w++){//输出图像(w,h)处像素映射到原图像中的坐标值,即插值坐标coordinateX = int(w / ratioX + 0.5);coordinateY = int(h / ratioY + 0.5);//若插值位置在输入图像范围内,则近邻插值if (coordinateX >= 0 && coordinateX <= width_p&&coordinateY >= 0 && coordinateY <= height_p){for (k = 0; k < pixelByte; k++){*(transBuf + h*lineByteOut + w*pixelByte + k)= *(dataBuf + coordinateY*lineByte + coordinateX*pixelByte + k);}}}}delete[] dataBuf;dataBuf = transBuf;}void Bitmap::dbLinearInterpolatin(float ratioX, float ratioY){int pixelByte = bitCount / 8;//每像素字节数int widthOut = int(ratioX*width_p);//输出图像宽度和高度int heightOut = int(ratioY*height_p);int lineByte = (width_p*bitCount / 8 + 3) / 4 * 4;//原图像每行像素的字节数int lineByteOut = (widthOut*bitCount / 8 + 3) / 4 * 4;//变换后图像每行像素的字节数unsigned char* transBuf = new unsigned char[lineByteOut*heightOut];int w, h;int k;//输出图像对应在输入图像中待插值的位置坐标float coordinateX, coordinateY;//临时变量,待插值位置向下取整的坐标int Iu, Iv;//数组,存放插值位置周围的4个像素unsigned char array[2][2];//双线性插值for (h = 0; h< heightOut; h++){for (w = 0; w< widthOut; w++){//输出图像坐标为(j,i)的像素映射到原图中的坐标值,即插值位置coordinateX = w / ratioX;coordinateY = h / ratioY;//对插值位置坐标取整Iu = (int)coordinateX;Iv = (int)coordinateY;//若插值位置在输入图像范围内,则双线性插值if (0 <= coordinateX&&coordinateX<width_p&& coordinateY >= 0 && coordinateY<height_p){//将图像每个像素通道的数据进行分别插值,//彩图pixelByte为3,灰度图像pixelByte为1for (k = 0; k<pixelByte; k++){//将第k个通道的四个像素数据拷贝至array数组中array[0][0] = *(dataBuf + Iv*lineByte + Iu*pixelByte + k);array[0][1] = *(dataBuf + Iv*lineByte + (Iu + 1)*pixelByte + k);array[1][0] = *(dataBuf + (Iv + 1)*lineByte + Iu*pixelByte + k);array[1][1] = *(dataBuf + (Iv + 1)*lineByte + (Iu + 1)*pixelByte + k);//两个中间变量int t1, t2;float ypos, xpos;ypos = coordinateY - Iv;xpos = coordinateX - Iu;//先垂直方向线性插值t1 = (1 - ypos)*array[0][0] + ypos*array[1][0];t2 = (1 - ypos)*array[0][1] + ypos*array[1][1];//再水平方向线性插值float t = (int)((1 - xpos)*t1 + xpos*t2);//若插值结果小于0,则输出0if (t<0)t = 0;//若插值结果大于255,则输出255if (t>255)t = 255;//调用双线性插值函数插值并输出到transBuf中*(transBuf + h * lineByteOut + w*pixelByte + k) = t;}}else{//边缘像素采用近邻插值for (k = 0; k<pixelByte; k++)*(transBuf + h * lineByteOut + w*pixelByte + k) =*(dataBuf + Iv*lineByte + Iu*pixelByte + k);}}}delete[] dataBuf;dataBuf = transBuf;}void Bitmap::cubicConvoInterpolatin(float ratioX, float ratioY){int pixelByte = bitCount / 8;//每像素字节数int widthOut = int(ratioX*width_p);//输出图像宽度和高度int heightOut = int(ratioY*height_p);int lineByte = (width_p*bitCount / 8 + 3) / 4 * 4;//原图像每行像素的字节数int lineByteOut = (widthOut*bitCount / 8 + 3) / 4 * 4;//变换后图像每行像素的字节数unsigned char* transBuf = new unsigned char[lineByteOut*heightOut];int w, h;int k;//输出图像对应在输入图像中待插值的位置坐标float coordinateX, coordinateY;//临时变量,待插值位置向下取整的坐标int Iu, Iv;//数组,存放插值位置周围16个像素unsigned char array[4][4];//循环变量,遍历待插值位置4x4的图像数据int  x, y;//立方卷积插值for (h = 0; h< heightOut; h++){for (w = 0; w< widthOut; w++){//输出图像坐标为(j,i)的像素映射到原图中的坐标值,即插值位置coordinateX = w / ratioX;coordinateY = h / ratioY;//对插值位置坐标取整Iu = (int)coordinateX;Iv = (int)coordinateY;//若插值位置在输入图像范围内,则立方卷积插值if (1 <= coordinateX&&coordinateX<width_p - 2&& coordinateY >= 1 && coordinateY<height_p - 2){//将图像每个像素通道的数据进行分别插值,//彩图pixelByte为3,灰度图像pixelByte为1for (k = 0; k<pixelByte; k++){//将第k个通道的4x4个像素数据拷贝至array数组中for (y = Iv - 1; y<Iv + 3; y++){for (x = Iu - 1; x<Iu + 3; x++){array[y - Iv + 1][x - Iu + 1] =*(dataBuf + y*lineByte + x*pixelByte + k);}}float xpos = coordinateX - Iu;float ypos = coordinateY - Iv;//申请数组,计算插值所需要的系数float col[4], row[4];//准备插值的x方向数据源col[0] = xpos + 1;col[1] = xpos;col[2] = 1 - xpos;col[3] = 2 - xpos;//准备插值的y方向数据源row[0] = ypos + 1;row[1] = ypos;row[2] = 1 - ypos;row[3] = 2 - ypos;//循环变量int i;//临时变量float t;//对水平方向系数数组进行计算for (i = 0; i<4; i++){t = fabs(col[i]);if (t >= 0 && t<1)col[i] = pow(t, 3) - 2 * pow(t, 2) + 1;else if (t >= 1 && t<2)col[i] = -pow(t, 3) + 5 * pow(t, 2) - 8 * t + 4;elsecol[i] = 0;}//对垂直方向系数数组进行计算for (i = 0; i<4; i++){t = fabs(row[i]);if (t >= 0 && t<1)row[i] = pow(t, 3) - 2 * pow(t, 2) + 1;else if (t >= 1 && t<2)row[i] = -pow(t, 3) + 5 * pow(t, 2) - 8 * t + 4;elserow[i] = 0;}//将计算好的系数与对应图像数据数组作卷积float tempArray[4], temp;//先x方向卷积for (i = 0; i<4; i++)tempArray[i] = row[0] * array[0][i] + row[1] * array[1][i] + row[2] * array[2][i] + row[3] * array[3][i];//再y方向卷积temp = 0;for (i = 0; i<4; i++)temp += tempArray[i] * col[i];//将插值结果在图像灰度级范围内输出if (temp>255)temp = 255;if (temp<0)temp = 0;//调用立方卷积插值函数插值并输出到transBuf中*(transBuf + h * lineByteOut + w*pixelByte + k) = (unsigned char)temp;}}else{//边缘像素采用近邻插值for (k = 0; k<pixelByte; k++)*(transBuf + h * lineByteOut + w*pixelByte + k) =*(dataBuf + Iv*lineByte + Iu*pixelByte + k);}}}}void Bitmap::rotate(float angle){int pixelByte = bitCount / 8;//每像素字节数int lineByte = (width_p*bitCount / 8 + 3) / 4 * 4;//原图像每行像素的字节数// 旋转角度(弧度), 将旋转角度从度转换到弧度float fRotateAngle = 2 * 3.1415926*angle / 360;// 输入图像四个角的坐标,以图像中心为坐标系原点float fSrcX1, fSrcY1, fSrcX2, fSrcY2, fSrcX3, fSrcY3, fSrcX4, fSrcY4;// 旋转后四个角的坐标,以图像中心为坐标系原点float fDstX1, fDstY1, fDstX2, fDstY2, fDstX3, fDstY3, fDstX4, fDstY4;// 计算旋转角度的正弦float fSina = (float)sin((double)fRotateAngle);// 计算旋转角度的余弦float fCosa = (float)cos((double)fRotateAngle);// 计算原图的四个角的坐标,以图像中心为坐标系原点fSrcX1 = (float)(-(width_p - 1) / 2);fSrcY1 = (float)((height_p - 1) / 2);fSrcX2 = (float)((width_p - 1) / 2);fSrcY2 = (float)((height_p - 1) / 2);fSrcX3 = (float)(-(width_p - 1) / 2);fSrcY3 = (float)(-(height_p - 1) / 2);fSrcX4 = (float)((width_p - 1) / 2);fSrcY4 = (float)(-(height_p - 1) / 2);// 计算新图四个角的坐标,以图像中心为坐标系原点fDstX1 = fCosa * fSrcX1 + fSina * fSrcY1;fDstY1 = -fSina * fSrcX1 + fCosa * fSrcY1;fDstX2 = fCosa * fSrcX2 + fSina * fSrcY2;fDstY2 = -fSina * fSrcX2 + fCosa * fSrcY2;fDstX3 = fCosa * fSrcX3 + fSina * fSrcY3;fDstY3 = -fSina * fSrcX3 + fCosa * fSrcY3;fDstX4 = fCosa * fSrcX4 + fSina * fSrcY4;fDstY4 = -fSina * fSrcX4 + fCosa * fSrcY4;// 旋转后输出图像宽度int width_pOut = (int)(max(fabs(fDstX4 - fDstX1), fabs(fDstX3 - fDstX2)) + 0.5);// 旋转后输出图像高度int height_pOut = (int)(max(fabs(fDstY4 - fDstY1), fabs(fDstY3 - fDstY2)) + 0.5);// 旋转后输出图像每行的字节数int lineByteOut = (width_pOut*pixelByte + 3) / 4 * 4;//分配缓冲区,存放旋转结果unsigned char* transBuf = new unsigned char[lineByteOut*height_pOut];memset(transBuf, 0, lineByteOut*height_pOut);// 两个常数,这样不用以后每次都计算了float f1 = (float)(-0.5 * (width_pOut - 1) * fCosa+ 0.5 * (height_pOut - 1) * fSina + 0.5 * (width_p - 1));float f2 = (float)(-0.5 * (width_pOut - 1) * fSina- 0.5 * (height_pOut - 1) * fCosa + 0.5 * (height_p - 1));// 循环变量,输出图像坐标int i, j;//循环变量,像素的每个通道int k;//输出图像在输入图像中待插值的位置坐标,必须浮点型int coordinateX, coordinateY;// 最近邻插值旋转for (i = 0; i < height_pOut; i++){for (j = 0; j < width_pOut; j++){// 输出图像像素(j,i)映射到输入图像的坐标,近邻插值取整数coordinateX = (int)(j * fCosa - i * fSina + f1 + 0.5);coordinateY = (int)(j * fSina + i * fCosa + f2 + 0.5);// 判断是否在输入图像范围内if ((coordinateX >= 0) && (coordinateX <= width_p) && (coordinateY >= 0)&& (coordinateY <=height_p)){//将图像每个通道的数据进行分别插值,彩色图像pixelByte为3,//灰度图像pixelByte为1for (k = 0; k<pixelByte; k++)*(transBuf + i*lineByteOut + j*pixelByte + k)= *(dataBuf + coordinateY*lineByte + coordinateX*pixelByte + k);}//else//{// // 对于不在原图中的像素,赋值为255// for (k = 0; k<pixelByte; k++)// *(transBuf + i*lineByteOut + j*pixelByte + k) = 255;//}}}delete[] dataBuf;dataBuf = transBuf;}

测试

#include"bmp.h"#include<iostream>using namespace std;int main(){char* fileName = "qianxun.bmp";Bitmap* bmp = new Bitmap();bmp->read(fileName);bmp->translation(10, 10);//bmp->zoom(2, 2, 'n');//'n','l','c';默认为'n'邻近插值缩放//bmp->rotate(90);bmp->write("translation.bmp");delete bmp;return 1;}






0 0
原创粉丝点击