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

图像的几何变换

#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为1
for (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,则输出0
if (t<0)
t = 0;
//若插值结果大于255,则输出255
if (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为1
for (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;
else
col[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;
else
row[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为1
for (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;
}






你可能感兴趣的:(C++,Visual,图像处理,位图,几何变换)