Cimage类处理图像像素(数据)的3种方式(转)

2023-03-07,,

这里只讨论对图像像素的处理,cimage类的具体用法查相关资料
#include <atlimage.h>   //VS2010以后不用加这个
 ……………………
CImage  m_Image;     //或CImage*  m_Image;  下面例子程序我用的CImage  m_Image; 只是一个用成员选择符,一个用指针操作,效率上可能有所差异

下面是3种方法:

一、用Cimage类的成员函数进行处理

这里假设你已经加载了图像位图,并与CImage对象m_Image相关联。相关成员函数主要有:

GetPixel 返回像素颜色

SetPixel 设置像素颜色

如:m_Image.SetPixel(  i-1,  j-1,  RGB(rr,gg,bb));

SetPixelRGB 设置像素的红绿蓝

如:m_Image.SetPixelRGB(x,y,avg,avg,avg);

SetColorTable 设置调色板颜色分量(红、绿、蓝)值

GetWidth 宽度(以像素为单位)

GetHeight 高度

1、程序示例

1)一个双线性插值放大程序。

    if  (m_Image.IsNull())
    return;
    // 创建对话框
    DlgInterpolation TranPara;
    //显示对话框,提示用户设定量
    if (TranPara.DoModal() != IDOK)
    return;
    int k=TranPara.m_inter;
    BeginWaitCursor();
    CImage  m_Image1;
    if (! m_Image1.IsNull())
    {
    m_Image1.Destroy();
    }
    m_Image1.Create( m_Image.GetWidth()*k, m_Image.GetHeight()*k, 24,0);
    // 四个最临近象素的坐标
    int x1, x2;
    int y1, y2;
    // 四个最临近象素值
    unsigned char   f1, f2, f3, f4;
    // 二个插值中间值
    unsigned char   f12, f34;
    //计算结果
    int fr,fb,fg;
    double  epsilon = 0.001;
    COLORREF pixel11,pixel12,pixel21,pixel22;
    int nHeight1 = m_Image1.GetHeight();
    int nWidth1 = m_Image1.GetWidth();
    int nHeight = m_Image.GetHeight();
    int nWidth = m_Image.GetWidth();
    double m=((double)nWidth1-1)/((double)nWidth-1);
    for  (int  i=0;  i<nWidth1;  i++)
    {
    for  (int  j=0;  j<nHeight1;  j++)
    {
    double x=double((double)i/m);
    double y=double((double)j/m);
    //计算四个最临近象素的坐标,+1向右下方移动
    x1 = (int) x;
    x2 = x1 + 1;
    y1 = (int) y;
    y2 = y1 + 1;
    if( (x < 0) || (x > nWidth - 1) || (y < 0) || (y > nHeight - 1))
    {
    //要计算的点不在源图范围内,返回-1
    continue;
    }
    else
    {
    if (fabs(x - nWidth + 1) <= epsilon )
    {
    // 要计算的点在图像右边缘上
    if (fabs(y -nHeight + 1) <= epsilon)
    {
    // 要计算的点正好是图像最右下角那一个象素,直接返回该点象素值
    pixel11 = m_Image.GetPixel(x1,y1);
    f1 = (unsigned char)GetRValue(pixel11);
    fr=(int)f1;
    f1 = (unsigned char)GetGValue(pixel11);
    fg=(int)f1;
    f1 = (unsigned char)GetBValue(pixel11);
    fb=(int)f1;
    }
    else
    {
    // 在图像右边缘上且不是最后一点,直接一次插值即可
    pixel11 = m_Image.GetPixel(x1,y1);
    pixel12 = m_Image.GetPixel(x1,y2);
    f1 = (unsigned char)GetRValue(pixel11);
    f3 = (unsigned char)GetRValue(pixel12);
    fr= (int) (f1 + (y -y1) * (f3 - f1));
    f1 = (unsigned char)GetGValue(pixel11);
    f3 = (unsigned char)GetGValue(pixel12);
    fg= (int) (f1 + (y -y1) * (f3 - f1));
    f1 = (unsigned char)GetBValue(pixel11);
    f3 = (unsigned char)GetBValue(pixel12);
    fb= (int) (f1 + (y -y1) * (f3 - f1));
    }
    }
    else if (fabs(y - nHeight + 1) <= epsilon)
    {
    // 要计算的点在图像下边缘上且不是最后一点,直接一次插值即可
    pixel11 = m_Image.GetPixel(x1,y1);
    pixel21 = m_Image.GetPixel(x2,y1);
    f1 = (unsigned char)GetRValue(pixel11);
    f2 = (unsigned char)GetRValue(pixel21);
    fr=(int) (f1 + (x -x1) * (f2 - f1));
    f1 = (unsigned char)GetGValue(pixel11);
    f2 = (unsigned char)GetGValue(pixel21);
    fg=(int) (f1 + (x -x1) * (f2 - f1));
    f1 = (unsigned char)GetBValue(pixel11);
    f2 = (unsigned char)GetBValue(pixel21);
    fb=(int) (f1 + (x -x1) * (f2 - f1));
    }
    else
    {
    pixel11 = m_Image.GetPixel(x1,y1);
    pixel12 = m_Image.GetPixel(x1,y2);
    pixel21 = m_Image.GetPixel(x2,y1);
    pixel22 = m_Image.GetPixel(x2,y2);
    // 计算四个最临近象素值
    f1 = (unsigned char)GetRValue(pixel11);
    f2 = (unsigned char)GetRValue(pixel21);
    f3 = (unsigned char)GetRValue(pixel12);
    f4 = (unsigned char)GetRValue(pixel22);
    f12 = (unsigned char) (f1 + (x - x1) * (f2 - f1));
    f34 = (unsigned char) (f3 + (x - x1) * (f4 - f3));
    fr= (int) (f12 + (y -y1) * (f34 - f12));
    f1 = (unsigned char)GetGValue(pixel11);
    f2 = (unsigned char)GetGValue(pixel21);
    f3 = (unsigned char)GetGValue(pixel12);
    f4 = (unsigned char)GetGValue(pixel22);
    f12 = (unsigned char) (f1 + (x - x1) * (f2 - f1));
    f34 = (unsigned char) (f3 + (x - x1) * (f4 - f3));
    fg= (int) (f12 + (y -y1) * (f34 - f12));
    f1 = (unsigned char)GetBValue(pixel11);
    f2 = (unsigned char)GetBValue(pixel21);
    f3 = (unsigned char)GetBValue(pixel12);
    f4 = (unsigned char)GetBValue(pixel22);
    f12 = (unsigned char) (f1 + (x - x1) * (f2 - f1));
    f34 = (unsigned char) (f3 + (x - x1) * (f4 - f3));
    fb= (int) (f12 + (y -y1) * (f34 - f12));
    }
    }
    m_Image1.SetPixel(i,j,  RGB(fr,fg,fb));
    }
    }
    m_Image.Destroy();
    m_Image.Create( m_Image1.GetWidth(), m_Image1.GetHeight(), 24, 0);
    COLORREF pixel;
    for  (int  i=0;  i<nWidth1;  i++)
    {
    for  (int  j=0;  j<nHeight1;  j++)
    {
    pixel = m_Image1.GetPixel(i,j);
    int y=GetRValue(pixel);
    int p=GetGValue(pixel);
    int b=GetBValue(pixel);
    m_Image.SetPixelRGB(i,j,GetRValue(pixel),GetGValue(pixel),GetBValue(pixel));
    }
    }
    m_Image1.Destroy();
    Invalidate();
    EndWaitCursor();

2)处理视频帧

    ……
    Defog(imageprosses, nimgWidth, nimgheigt);/*我加的一个雾天图像增强的动态库,imageprosses是视频的一帧,输入imageprosses处理,并输出imageprosses*/
    int  rr  =  0,  gg  =  0,  bb  =  0;
    for  (int i  =  0;  i  < nimgWidth;  i++)
    {
    for  (int j  =  1;  j  <= nimgheigt;  j++)
    {
    bb=(int)imageprosses[3*i*j];
    gg=(int)imageprosses[3*i*j+1];
    rr=(int)imageprosses[3*i*j+2];
    m_Image.SetPixel(i,  j-1,  RGB(rr,gg,bb));/*设置一帧图像的像素值用来显示*/
    }
    }
    ……

2、比较:非常慢。一个图像数据一般很大的,函数调用、参数传递会更加耗时。

二、直接对内存进行操作

相关成员函数:

GetPitch 行距

GetBPP 每像素位数,用时记得GetBPP()/8

GetBits 返回图像像素数据指针

1、程序示例

    ……
    Defog(imageprosses, nimgWidth, nimgheigt);
    //调用cimage类
    if  (m_Image.IsNull())
    m_Image.Create( nimgWidth, nimgheigt, 24,0);
    //地址访问方式
    byte* pRealData;
    //首地址
    pRealData=(byte*)m_Image.GetBits();
    //行距
    int pit=m_Image.GetPitch();
    for  (int i  =  0;  i  <nimgWidth;  i++)
    {
    for  (int j  =  0;  j  < nimgheigt;  j++)
    {
    *(pRealData + pit*j+ i*3)=(int)imageprosses[3*(nimgheigt-1-j)*nimgWidth+3*i];
    *(pRealData + pit*j +i*3 +1)=(int)imageprosses[3*(nimgheigt-1-j)*nimgWidth+3*i+1];
    *(pRealData + pit*j + i*3 +2)=(int)imageprosses[3*(nimgheigt-1-j)*nimgWidth+3*i+2];
    }
    }
    m_Image.Draw(pDC->m_hDC,0,0,nWidth,nheigt);
    ……

2、比较: 对地址直接操作最快,不需要多余的转换。

三、用数组进行处理

如果处理比较复杂的话,可把所有点颜色全部读到一个二维数组里面,然后对这个数组进行读写和处理。 再把处理后的图像显示出来。最方便的是可以进行一些自己需要的预处理,比如我是这样做的。

首先定义一个相关头文件和源文件处理相关内存操作

//MYIMAGE.h

    #if !defined(MyIMAGE)
    #define MyIMAGE
    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000
    #include "windows.h"
    // 灰度图
    typedef byte **MYIMAGE;/*二维数组的数组名就是一个指向指针的指针,a的作用相当于**a,而a->[0],相当于a[0][0]*/
    //彩色图
    typedef struct MYCOLORIMAGESTRUCT
    {
    MYIMAGE r, g, b;
    }MYCOLORIMAGE;
    ////// 8bit图像操作
    // 8bit图像分配
    MYIMAGE MyImageAlloc(int height,int width);
    // 8bit图像释放
    void MyImageFree(MYIMAGE a, int height);
    // 8bit图像拷贝
    bool MyImageCopy(MYIMAGE dest, MYIMAGE source, int width, int height);
    // 8bit图像设置
    void MyImageSet(MYIMAGE a, int value, int width, int height);
    ////// 24bit图像操作
    // 24bit图像分配
    MYCOLORIMAGE MyColorImageAlloc(int height,int width);
    // 24bit图像释放
    void MyColorImageFree(MYCOLORIMAGE a, int height);
    // 24bit图像拷贝
    bool MyColorImageCopy(MYCOLORIMAGE dest, MYCOLORIMAGE source, int width, int height);
    // 24bit图像设置
    void MyColorImagSet(MYCOLORIMAGE a, int value, int width, int height);
    // 彩色图像转灰度图象
    bool MyColorToGray(MYIMAGE outGrayImg, MYCOLORIMAGE inColorImg, int width, int Height);
    #endif MyIMAGE

//MYIMAGE.cpp

    #include "StdAfx.h"
    #include "MYIMAGE.h"
    //灰度图像
    /**************my分配内存空间***************/
    MYIMAGE MyImageAlloc(int height,int width)
    {
    MYIMAGE a = (MYIMAGE) new MYIMAGE*[height];//数组指针
    int i;
    byte* pTemp;
    pTemp = new UCHAR[height*width];
    for(i = 0; i < height; i++)
    {
    a[i] = pTemp + width * i;
    }
    return a;
    }
    /*********释放内存空间***************/
    void MyImageFree(MYIMAGE a, int height)
    {
    delete[] a[0];
    delete a;
    }
    /*******拷贝************/
    bool MyImageCopy(MYIMAGE dest, MYIMAGE source, int width, int height)
    {
    if(dest == NULL || source == NULL || width <= 0 || height <= 0)
    return false;
    int i = 0;
    for(i = 0; i < height; i++)
    {
    memcpy(dest[i], source[i], sizeof(UCHAR) * width);
    }
    return true;
    }
    /*******赋值*******/
    void MyImageSet(MYIMAGE a, int value, int width, int height)
    {
    int i;
    for(i = 0; i < height; i++)
    {
    memset(a[i], value, sizeof(UCHAR) * width);
    }
    }
    //彩色图像
    /**************my彩色图像分配内存空间**********************/
    MYCOLORIMAGE MyColorImageAlloc(int height,int width)
    {
    //MYCOLORIMAGE a = (MYCOLORIMAGE) new char[sizeof(MYIMAGE) * 3];
    MYCOLORIMAGE a;
    a.r = MyImageAlloc(height,width);
    a.g = MyImageAlloc(height,width);
    a.b = MyImageAlloc(height,width);
    return a;
    }
    /****************my彩色图像空间内存释放*********************/
    void MyColorImageFree(MYCOLORIMAGE a, int height)
    {
    /*
    MyImageFree(a->r, height);
    MyImageFree(a->g, height);
    MyImageFree(a->b, height);
    delete a;
    */
    MyImageFree(a.r, height);
    MyImageFree(a.g, height);
    MyImageFree(a.b, height);
    }
    /***************my彩色图像拷贝******************/
    bool MyColorImageCopy(MYCOLORIMAGE dest, MYCOLORIMAGE source, int width, int height)
    {
    /*
    if(dest == NULL || source == NULL || width <= 0 || height <= 0)
    return false;
    int i = 0;
    for(i = 0; i < height; i++)
    {
    memcpy(dest->r[i], source->r[i], sizeof(UCHAR) * width);
    memcpy(dest->g[i], source->g[i], sizeof(UCHAR) * width);
    memcpy(dest->b[i], source->b[i], sizeof(UCHAR) * width);
    }
    return true;
    */
    if(dest.r == NULL || source.r == NULL || width <= 0 || height <= 0)
    return false;
    for(int i = 0; i < height; i++)
    {
    memcpy(dest.r[i], source.r[i], sizeof(UCHAR) * width);
    memcpy(dest.g[i], source.g[i], sizeof(UCHAR) * width);
    memcpy(dest.b[i], source.b[i], sizeof(UCHAR) * width);
    }
    return true;
    }
    /**********my彩色图像赋值*****************/
    void MyColorImagSet(MYCOLORIMAGE a, int value, int width, int height)
    {
    int i;
    for(i = 0; i < height; i++)
    {
    memset(a.r[i], value, sizeof(UCHAR) * width);
    memset(a.g[i], value, sizeof(UCHAR) * width);
    memset(a.b[i], value, sizeof(UCHAR) * width);
    }
    }
    /**********my彩色图转为灰度图**************/
    bool MyColorToGray(MYIMAGE outGrayImg, MYCOLORIMAGE inColorImg, int width, int Height)
    {
    if(outGrayImg == NULL || inColorImg.r == NULL || width <= 0 || Height <= 0)
    return false;
    for(int j = 0; j < Height; j++)
    {
    for(int i = 0; i < width; i++)
    {
    outGrayImg[j][i] = (int)(0.3 * inColorImg.r[j][i] + 0.59 * inColorImg.g[j][i] + 0.11 * inColorImg.b[j][i]);
    }
    }
    return TRUE;
    }

然后一些预处理操作,如格式间转换:

//ImageTransform.h

    #if !defined(ImageTransform)
    #define ImageTransform
    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000
    //#include "ximage.h"
    #include "MYIMAGE.h"
    #include "atlimage.h"
    //CImage到MYIMAGE之间的格式转换
    //灰度
    // CImage转换成MYIMAGE
    BOOL CxImageToMYIMAGE(MYIMAGE destpImgbuf, CImage&  sourpCxImage, int nImgWidth, int nImgHeight);
    // MYIMAGE转换成CImage
    BOOL MYIMAGEToCxImage(CImage&  destpCxImage,  MYIMAGE sourpImgbuf, int nImgWidth, int nImgHeight);
    //彩色
    // CImage转换成MYCOLORIMAGE
    BOOL CxxImageToMYIMAGE(MYCOLORIMAGE destpImgbuf, CImage&  sourpCxImage, int nImgWidth, int nImgHeight);
    // MYCOLORIMAGE转换成CImage
    BOOL MYIMAGEToCxxImage(CImage&  destpCxImage,  MYCOLORIMAGE sourpImgbuf, int nImgWidth, int nImgHeight);
    #endif ImageTransform

//ImageTransform.cpp

    #include "StdAfx.h"
    #include "ImageTransform.h"
    //灰度
    //  CImage转换成MYIMAGE
    BOOL CxImageToMYIMAGE(MYIMAGE destpImgbuf, CImage&  sourpCxImage, int nImgWidth, int nImgHeight)
    {
    // 参数检查
    if(destpImgbuf == NULL || sourpCxImage == NULL || nImgWidth <= 0 || nImgHeight <= 0)
    return FALSE;
    int i, j;
    COLORREF rgb;
    //8位灰度图转存为8位灰度图
    if(sourpCxImage.GetBPP()/8 ==1)
    {
    for(j = 0; j < nImgHeight; j++)
    {
    for(i = 0; i < nImgWidth; i++)
    {
    destpImgbuf[j][i] = (byte)sourpCxImage.GetPixel(i, j);
    }
    }
    }
    //24位灰度图象转换为8位灰度图
    else if(sourpCxImage.GetBPP()/8==3)
    {
    for(j = 0; j < nImgHeight; j++)
    {
    for(i = 0; i < nImgWidth; i++)
    {
    rgb = sourpCxImage.GetPixel(i, j);
    destpImgbuf[j][i] = GetRValue(rgb);
    }
    }
    }
    return TRUE;
    }
    // MYIMAGE转换成CImage
    BOOL MYIMAGEToCxImage(CImage& destpCxImage, MYIMAGE sourpImgbuf, int nImgWidth, int nImgHeight)
    {
    // 参数检查
    if(destpCxImage == NULL || sourpImgbuf == NULL || nImgWidth <= 0 || nImgHeight <= 0)
    return FALSE;
    int i, j;
    //8位灰度图转换为24位灰度图
    for(j = 0; j < nImgHeight; j++)
    {
    for(i = 0; i < nImgWidth; i++)
    {
    destpCxImage.SetPixelRGB(i, j, sourpImgbuf[j][i],sourpImgbuf[j][i],sourpImgbuf[j][i]);
    }
    }
    return TRUE;
    }
    //24位真彩色
    //CImage转换成MYCOLORIMAGE
    BOOL CxxImageToMYIMAGE(MYCOLORIMAGE destpImgbuf, CImage& sourpCxImage, int nImgWidth, int nImgHeight)
    {
    // 参数检查
    if(destpImgbuf.r == NULL || sourpCxImage == NULL || nImgWidth <= 0 || nImgHeight <= 0)
    return FALSE;
    int i, j;
    COLORREF rgb;
    //24位转换为24位存储
    for(j = 0; j < nImgHeight; j++)
    {
    for(i = 0; i < nImgWidth; i++)
    {
    rgb=sourpCxImage.GetPixel(i, j);
    destpImgbuf.r[j][i] = GetRValue(rgb);
    destpImgbuf.g[j][i] = GetGValue(rgb) ;
    destpImgbuf.b[j][i] = GetBValue(rgb) ;
    }
    }
    return TRUE;
    }
    //MYCOLORIMAGE转换成CImage
    BOOL MYIMAGEToCxxImage(CImage& destpCxImage, MYCOLORIMAGE sourpImgbuf, int nImgWidth, int nImgHeight)
    {
    // 参数检查
    if(destpCxImage == NULL || sourpImgbuf.r == NULL || nImgWidth <= 0 || nImgHeight <= 0)
    return FALSE;
    int i, j;
    //24位转换为24位存储
    for(j = 0; j < nImgHeight; j++)
    {
    for(i = 0; i < nImgWidth; i++)
    {
    destpCxImage.SetPixelRGB(i, j,sourpImgbuf.r[j][i],sourpImgbuf.g[j][i],sourpImgbuf.b[j][i]);
    }
    }
    return TRUE;
    }

1、程序示例,一个Laplacian算子进行锐化的例子。

    //模版系数取1
    if  (m_Image.IsNull())
    return;
    BeginWaitCursor();
    if  (!m_Img.IsNull())
    m_Img.Destroy();
    m_Img.Create( m_Image.GetWidth(), m_Image.GetHeight(), 24,0);
    int  nWidth  =  m_Image.GetWidth();
    int  nHeight  =  m_Image.GetHeight();
    MYIMAGE RData=NULL;
    MYIMAGE GData=NULL;
    MYIMAGE BData=NULL;
    RData=MyImageAlloc(nHeight,nWidth);
    GData=MyImageAlloc(nHeight,nWidth);
    BData=MyImageAlloc(nHeight,nWidth);
    COLORREF color ;
    for(int j = 0;j<nWidth;j++)
    for(int i = 0;i<nHeight; i++)
    {
    color = m_Image.GetPixel(j,i);
    RData[i][j]= GetRValue(color);
    GData[i][j]= GetGValue(color);
    BData[i][j]= GetBValue(color);
    }
    int  templ[9]  =  {0,-1,0,-1,4,-1,0,-1,0};
    for  (int i  =  1;  i  <  nWidth-1;  i++)
    {
    for  (int j  =  1;  j  <  nHeight-1;  j++)
    {
    int  r =  0,  g=  0,  b =  0;
    int  index  =  0;
    //模版1
    for  (int  col  =  -1;  col  <=  1;  col++)
    {
    for  (int  row  =  -1;  row  <=  1;  row++)
    {
    r+=  RData[j+row][i+col] * templ[index];
    g+=  GData[j+row][i+col] * templ[index];
    b+=  BData[j+row][i+col] * templ[index];
    index++;
    }
    }
    if   (  r  <  0  )  r  =  -r;
    else  if (  r  >  255  )  r  =  255;
    if   (  g  <  0  )  g  = -g;
    else  if  (  g  >  255  )  g  =  255;
    if  (  b  <  0  )  b  = -b;
    else  if  (  b  >  255  )  b  =  255;
    m_Img.SetPixelRGB(i,j,r,g,b);
    }
    }
    MyImageFree(RData, nHeight);
    MyImageFree(GData, nHeight);
    MyImageFree(BData, nHeight);
    Invalidate();
    EndWaitCursor();

2、比较:比较方便也比较快

Cimage类处理图像像素(数据)的3种方式(转)的相关教程结束。

《Cimage类处理图像像素(数据)的3种方式(转).doc》

下载本文的Word格式文档,以方便收藏与打印。