原文做者:aircrafthtml
原文地址:https://www.cnblogs.com/DOMLX/p/9598974.html前端
我看了一下發現關於CImage類 圖像處理相關的介紹真的是比較少,由於我要作大二的數據結構的課程設計,要用純c++語言去實現(老師不讓調用圖像處理庫),因此本身就嘗試寫了不少操做處理的代碼,下面都是我課設用到的代碼段,我已經下降耦合度分離出來了,如今就所有分享出來吧。python
前人栽樹,後人乘涼c++
望與諸君共勉。編程
MFC圖像處理CImage類經常使用操做後端
CImage類頭文件爲#include<atlimage.h>數組
CImage類讀取圖片CImage.Load("src.bmp");數據結構
CImage類保存圖片CImage.Save("dst.jpg");
機器學習
一.CImage類實例拷貝數據到另一個CImage類實例函數
bool ImageCopy(const CImage &srcImage, CImage &destImage) { int i, j;//循環變量 if (srcImage.IsNull()) return FALSE; //源圖像參數 BYTE* srcPtr = (BYTE*)srcImage.GetBits(); int srcBitsCount = srcImage.GetBPP(); int srcWidth = srcImage.GetWidth(); int srcHeight = srcImage.GetHeight(); int srcPitch = srcImage.GetPitch(); //銷燬原有圖像 if (!destImage.IsNull()) { destImage.Destroy(); } //建立CImage類新圖像並分配內存 if (srcBitsCount == 32) //支持alpha通道 { destImage.Create(srcWidth, srcHeight, srcBitsCount, 1); } else { destImage.Create(srcWidth, srcHeight, srcBitsCount, 0); } //加載調色板 if (srcBitsCount <= 8 && srcImage.IsIndexed())//須要調色板 { RGBQUAD pal[256]; int nColors = srcImage.GetMaxColorTableEntries(); if (nColors>0) { srcImage.GetColorTable(0, nColors, pal); destImage.SetColorTable(0, nColors, pal);//複製調色板程序 } } //目標圖像參數 BYTE *destPtr = (BYTE*)destImage.GetBits(); int destPitch = destImage.GetPitch(); //複製圖像數據 for (i = 0; i<srcHeight; i++) { memcpy(destPtr + i*destPitch, srcPtr + i*srcPitch, abs(srcPitch)); } return TRUE; }
二.CImage類實例處理圖像間的腐蝕運算
//腐蝕運算
//width:圖像寬;height:圖像高;矩形掩膜的邊長(2*r+1)void erosion(CImage image, int width, int height, int r) { int i, j, m, n; int flag; //unsigned char * pBuff = tempBuff; CImage Buff; ImageCopy(image, Buff); //dataCopy(image, pBuff, width, height); byte *pImg = (byte *)image.GetBits(); byte *pBuff = (byte *)Buff.GetBits(); int step = image.GetPitch(); //int height = image.GetHeight(); //int width = image.GetWidth(); for (i = r; i<height - r; i++) { for (j = r; j<width - r; j++) { flag = 1; for (m = i - r; m <= i + r; m++) { for (n = j - r; n <= j + r; n++) { //if (!pBuff[i*width + j] || !pBuff[m*width + n]) if (!*(pBuff + i*step + j) || !*(pBuff + m*step + n)) { flag = 0; break; } } } if (flag == 0) { *(pImg + i*step + j) = 0; } else { *(pImg + i*step + j) = 255; } } } }
三.CImage類實例處理圖像間的膨脹運算
//膨脹運算 //width:圖像寬;height:圖像高;矩形掩膜的邊長(2*r+1) void diate(CImage image, int width, int height, int r) { int i, j, m, n; int flag; //unsigned char * pBuff = tempBuff; CImage Buff; ImageCopy(image, Buff); //dataCopy(image, pBuff, width, height); byte *pImg = (byte *)image.GetBits(); byte *pBuff = (byte *)Buff.GetBits(); int step = image.GetPitch(); //int height = image.GetHeight(); //int width = image.GetWidth(); //dataCopy(image, pBuff, width, height); for (i = r; i<height - r; i++) { for (j = r; j<width - r; j++) { flag = 1; for (m = i - r; m <= i + r; m++) { for (n = j - r; n <= j + r; n++) { if (255 == *(pBuff + i*step + j) || 255 == *(pBuff + m*step + n)) { flag = 0; break; } } } if (flag == 0) { *(pImg + i*step + j) = 255; } else { *(pImg + i*step + j) = 0; } } } }
四.CImage類實例處理圖片遍歷賦值操做
byte *pImg = (byte *)imgSrc.GetBits(); int step = imgSrc.GetPitch(); int height = imgSrc.GetHeight(); int width = imgSrc.GetWidth(); int sum = 0; unsigned char val = 0; //初始化 for (int i = 0; i<maxY; i++) for (int j = 0; j<maxX; j++) *(pDstImg + i*step + j) = 0;
五.用CImage類實例遍歷生成手指靜脈邊緣圖
#define mlen 9 //模板長度 //加長擴展的水平邊緣檢測模板 int upperEdgeOperator[mlen * 3] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; int lowerEdgeOperator[mlen * 3] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; int findEdgesHorizontal(CImage& imgSrc, CImage& imgDst) { int maxY = imgSrc.GetHeight(); int maxX = imgSrc.GetWidth(); if (!imgDst.IsNull()) { imgDst.Destroy(); } imgDst.Create(maxX, maxY, 8, 0);//圖像大小與imgSrc相同,每一個像素佔1字節 if (imgDst.IsNull()) return FALSE; byte *pImg = (byte *)imgSrc.GetBits(); byte *pDstImg = (byte *)imgDst.GetBits(); int step = imgSrc.GetPitch(); int height = imgSrc.GetHeight(); int width = imgSrc.GetWidth(); int sum = 0; unsigned char val = 0; //初始化 for (int i = 0; i<maxY; i++) for (int j = 0; j<maxX; j++) *(pDstImg + i*step + j) = 0; //找上邊緣 for (int i = 1; i <maxY / 2 - 1; i++) { for (int j = 4; j < maxX - 4; j++) { sum = 0; for (int m = -1; m <= 1; m++) { for (int n = -mlen / 2; n <= mlen / 2; n++) { sum += *(pImg + (i + m)*step + (j + n))*upperEdgeOperator[(m + 1)*mlen + (n + mlen / 2)]; } } sum = sum < 0 ? 0 : sum; sum = sum > 255 ? 255 : sum; val = unsigned char(sum); *(pDstImg + i*step + j) = val; } } //找下邊緣 for (int i = maxY / 2 + 1; i <maxY - 1; i++) { for (int j = 4; j < maxX - 4; j++) { sum = 0; for (int m = -1; m <= 1; m++) { for (int n = -mlen / 2; n <= mlen / 2; n++) { sum += *(pImg + (i + m)*step + (j + n))*upperEdgeOperator[(m + 1)*mlen + (n + mlen / 2)];; } } sum = sum < 0 ? 0 : sum; sum = sum > 255 ? 255 : sum; val = unsigned char(sum); *(pDstImg + i*step + j) = val; } } return TRUE; }
六.CImage圖像類實例將RGB圖轉爲灰度(gary)圖
BOOL ImageToGray(CImage& imgSrc, CImage& imgDst) { int maxY = imgSrc.GetHeight(); int maxX = imgSrc.GetWidth(); if (!imgDst.IsNull()) { imgDst.Destroy(); } imgDst.Create(maxX, maxY, 8, 0);//圖像大小與imgSrc相同,每一個像素佔1字節 if (imgDst.IsNull()) return FALSE; //爲imgDst構造256階灰度調色表 RGBQUAD ColorTab[256]; for (int i = 0; i<256; i++) { ColorTab[i].rgbBlue = ColorTab[i].rgbGreen = ColorTab[i].rgbRed = i; } imgDst.SetColorTable(0, 256, ColorTab); byte* pDataSrc = (byte*)imgSrc.GetBits(); //獲取指向圖像數據的指針 byte* pDataDst = (byte*)imgDst.GetBits(); int pitchSrc = imgSrc.GetPitch(); //獲取每行圖像佔用的字節數 +:top-down;-:bottom-up DIB int pitchDst = imgDst.GetPitch(); int bitCountSrc = imgSrc.GetBPP() / 8; // 獲取每一個像素佔用的字節數 int bitCountDst = imgDst.GetBPP() / 8; if ((bitCountSrc != 3) || (bitCountDst != 1)) return FALSE; int tmpR, tmpG, tmpB, avg; for (int i = 0; i<maxX; i++) { for (int j = 0; j<maxY; j++) { tmpR = *(pDataSrc + pitchSrc*j + i*bitCountSrc); tmpG = *(pDataSrc + pitchSrc*j + i*bitCountSrc + 1); tmpB = *(pDataSrc + pitchSrc*j + i*bitCountSrc + 2); avg = (int)(tmpR + tmpG + tmpB) / 3; *(pDataDst + pitchDst*j + i*bitCountDst) = avg; } } return TRUE; }
七.CImage類轉opencv Mat類 以及Mat類轉CImage類
#include "stdafx.h" #include <opencv2/opencv.hpp> #include "CimgMat.h" void CimgMat::MatToCImage(Mat& mat, CImage& cimage) { if (0 == mat.total()) { return; } int nChannels = mat.channels(); if ((1 != nChannels) && (3 != nChannels)) { return; } int nWidth = mat.cols; int nHeight = mat.rows; //重建cimage cimage.Destroy(); cimage.Create(nWidth, nHeight, 8 * nChannels); //拷貝數據 uchar* pucRow; //指向數據區的行指針 uchar* pucImage = (uchar*)cimage.GetBits(); //指向數據區的指針 int nStep = cimage.GetPitch(); //每行的字節數,注意這個返回值有正有負 if (1 == nChannels) //對於單通道的圖像須要初始化調色板 { RGBQUAD* rgbquadColorTable; int nMaxColors = 256; rgbquadColorTable = new RGBQUAD[nMaxColors]; cimage.GetColorTable(0, nMaxColors, rgbquadColorTable); for (int nColor = 0; nColor < nMaxColors; nColor++) { rgbquadColorTable[nColor].rgbBlue = (uchar)nColor; rgbquadColorTable[nColor].rgbGreen = (uchar)nColor; rgbquadColorTable[nColor].rgbRed = (uchar)nColor; } cimage.SetColorTable(0, nMaxColors, rgbquadColorTable); delete[]rgbquadColorTable; } for (int nRow = 0; nRow < nHeight; nRow++) { pucRow = (mat.ptr<uchar>(nRow)); for (int nCol = 0; nCol < nWidth; nCol++) { if (1 == nChannels) { *(pucImage + nRow * nStep + nCol) = pucRow[nCol]; } else if (3 == nChannels) { for (int nCha = 0; nCha < 3; nCha++) { *(pucImage + nRow * nStep + nCol * 3 + nCha) = pucRow[nCol * 3 + nCha]; } } } } } void CimgMat::CImageToMat(CImage& cimage, Mat& mat) { if (true == cimage.IsNull()) { return; } int nChannels = cimage.GetBPP() / 8; if ((1 != nChannels) && (3 != nChannels)) { return; } int nWidth = cimage.GetWidth(); int nHeight = cimage.GetHeight(); //重建mat if (1 == nChannels) { mat.create(nHeight, nWidth, CV_8UC1); } else if (3 == nChannels) { mat.create(nHeight, nWidth, CV_8UC3); } //拷貝數據 uchar* pucRow; //指向數據區的行指針 uchar* pucImage = (uchar*)cimage.GetBits(); //指向數據區的指針 int nStep = cimage.GetPitch(); //每行的字節數,注意這個返回值有正有負 for (int nRow = 0; nRow < nHeight; nRow++) { pucRow = (mat.ptr<uchar>(nRow)); for (int nCol = 0; nCol < nWidth; nCol++) { if (1 == nChannels) { pucRow[nCol] = *(pucImage + nRow * nStep + nCol); } else if (3 == nChannels) { for (int nCha = 0; nCha < 3; nCha++) { pucRow[nCol * 3 + nCha] = *(pucImage + nRow * nStep + nCol * 3 + nCha); } } } } }
八.純圖像數據賦值給CImage後的初始化,而且寫入調色板
bool InitalImage(CImage &image, int width, int height) { if (image.IsNull()) image.Create(width, height, 8); else { if (width <= 0 || height <= 0) return false; else if (image.GetHeight() == width && image.GetWidth() == height) return true; else { image.Destroy(); image.Create(width, height, 8); } } //寫入調色板 RGBQUAD ColorTable[256]; image.GetColorTable(0, 256, ColorTable); for (int i = 0; i < 256; i++) { ColorTable[i].rgbBlue = (BYTE)i; ColorTable[i].rgbGreen = (BYTE)i; ColorTable[i].rgbRed = (BYTE)i; } image.SetColorTable(0, 256, ColorTable); return true; }
九.根據MFC控件大小CImage類實例圖片顯示
if(m_image2.IsNull()) //判斷有無圖像 return; // 取得客戶區尺寸 CRect zcRect; GetDlgItem(IDC_STATIC_PIC2)->GetClientRect(&zcRect); // 將圖像顯示在界面之上 m_image2.Draw(GetDlgItem(IDC_STATIC_PIC2)->GetDC()->m_hDC, zcRect.left, zcRect.top, zcRect.Width(), zcRect.Height());
十.根據CImage類實例圖片調整控件大小顯示圖片
if(m_image1.IsNull()) return; // 將整控件調整爲與圖像同一尺寸 GetDlgItem(IDC_STATIC_PIC)->SetWindowPos(NULL, 0,0,m_image1.GetWidth(), m_image1.GetHeight(), SWP_NOMOVE); CRect zcRect; GetDlgItem(IDC_STATIC_PIC)->GetClientRect(&zcRect); m_image1.Draw(GetDlgItem(IDC_STATIC_PIC)->GetDC()->m_hDC, zcRect.left, zcRect.top, zcRect.Width(), zcRect.Height());
十一.CImage類與CBitmap轉換
CImage nImage; nImage.Load(imgFilePath); HBITMAP hBitmap=nImage.Detach(); // 得到位圖句柄 用以轉換 // 轉換方式一: CBitmap bmp; bmp.DeleteObject(); bmp.Attach(hBitmap); // 轉換爲CBitmap對象 // 轉換方式二: CBitmap *pBitmap=CBitmap::FromHandle(nImage.m_hBitmap);
十二.CImage類實例實現圖像二值化
void imgBinary(CImage image, int imgW, int imgH, int threshold) { int i; int index = 0; byte *pImg = (byte *)image.GetBits(); int step = image.GetPitch(); int height = image.GetHeight(); int width = image.GetWidth(); for (i = 0; i<height*width; i++) { *(pImg + index) = *(pImg + index)>threshold ? 255 : 0; index++; } }
十三.CImage實現本身的argmax函數----求圖像必定高度區域中某一列遇到的第一個最大像素值得座標並返回
int argmax(CImage &image,int Top,int Bottom,int x) { int max = 0; int tem; int pos = 0; byte *pImg = (byte *)image.GetBits(); int step = image.GetPitch(); int height = image.GetHeight(); int width = image.GetWidth(); if (Top > 0 && Top < height && Bottom > 0 && Bottom < height && x > 0 && x < width) { for (int i = Top; i < Bottom; ++i) { tem = *(pImg + i*step + x); if (tem > max) { max = tem; pos = i; } } return pos; } else { return FALSE; } }
十四.CImage類建立指定長寬圖像並初始化調色板
bool InitalImage(CImage &image, int width, int height) { if (image.IsNull()) image.Create(width, height, 8); else { if (width <= 0 || height <= 0) return false; else if (image.GetHeight() == width && image.GetWidth() == height) return true; else { image.Destroy(); image.Create(width, height, 8); } } //寫入調色板 RGBQUAD ColorTable[256]; image.GetColorTable(0, 256, ColorTable); for (int i = 0; i < 256; i++) { ColorTable[i].rgbBlue = (BYTE)i; ColorTable[i].rgbGreen = (BYTE)i; ColorTable[i].rgbRed = (BYTE)i; } image.SetColorTable(0, 256, ColorTable); return true; }
十五.將存放在一維指針數組裏的圖像數據賦值給CImage類實例
void LoadImageData(CImage &image, unsigned char * data) { if (data == nullptr) return; byte *pS; byte *pImg = (byte *)image.GetBits(); int step = image.GetPitch(); int height = image.GetHeight(); int width = image.GetWidth(); for (int i = 0; i < image.GetHeight(); ++i) { pS = data + i * width; for (int j = 0; j < image.GetWidth(); ++j) { *(pImg + i*step + j) = pS[j]; } } }
十六.CImage類本身實現圖片的裁剪
//裁剪roi區域 void RoiCut(CImage &image, CImage &roiImg, int heightTop,int heightDown,int widthBegin,int widthEnd) { InitalImage(roiImg, heightDown - heightTop + 1, widthBegin - widthEnd + 1); byte *pImg = (byte *)image.GetBits(); byte *pRoi = (byte *)roiImg.GetBits(); int step = image.GetPitch(); int height = image.GetHeight(); int width = image.GetWidth(); int index = 0; for (int i = heightTop; i < heightDown; i++) { for (int j = widthBegin; j < widthEnd; j++) { *(pRoi + index) = *(pImg + i*step + j); index++; } } }
還有一些操做比較麻煩這裏就先不寫了,後面想到什麼在寫把嘿嘿。
參考博客:https://blog.csdn.net/ishallwin/article/details/4840180
參考博客:https://blog.csdn.net/shuilan0066/article/details/7080244
如有興趣交流分享技術,可關注本人公衆號,裏面會不按期的分享各類編程教程,和共享源碼,諸如研究分享關於c/c++,python,前端,後端,opencv,halcon,opengl,機器學習深度學習之類有關於基礎編程,圖像處理和機器視覺開發的知識