zoukankan      html  css  js  c++  java
  • 数字图像处理学习笔记(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;
    }






  • 相关阅读:
    [原]写项目方案书的六字方针
    [原]简述Field,Attribute,Property的区别
    [原]Excel(电子表格)中的大写变成小写
    [原]滚动的图片或文字(有缝)
    [原]按字母索引(asp版)
    [原]sql语句上一篇,下一篇
    [原]选中行后高亮显示
    自定义报表开发、使用手册
    男人必须终身牢记的一句话
    在sqlplus中操作blob和clob
  • 原文地址:https://www.cnblogs.com/corfox/p/5415024.html
Copyright © 2011-2022 走看看