這里只討論對圖像像素的處理,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、比較:比較方便也比較快