傳統圖像處理庫通常將圖像資料結構(像素儲存、色彩空間、幾何屬性)與演算法(濾波、幾何變換、色彩調整)綁定在同一個類別體系中,導致擴充新演算法需修改核心類別、或難以套用至既有專案的自訂圖像類別。本文介紹一個「通用圖像演算法擴充庫」,採用策略模式與非侵入式介面設計,僅提供演算法封裝與進度回呼,圖像物件本身由使用者自行定義,理論上可整合任何 C++ 圖像類別(如 CxImage、CDib、OpenCV Mat 等)。
本庫的設計動機源於《Crazybit 開發手記(一):設計之資料結構和演算法的分離》。核心觀點:
為達到零耦合,使用者需從 FCObjImage 派生自訂圖像類別,並實作下列純虛擬/約定方法(多為單行屬性存取):
| 方法原型 | 功能說明 | |
|---|---|---|
FCObjImage() | 預設建構函式 | |
FCObjImage(const FCObjImage&) | 拷貝建構函式 | |
operator=(const FCObjImage&) | 指派運算子 | |
IsValidImage() const | 圖像是否有效 | |
ColorBits() const | 色彩位深(1/4/8/16/24/32) | |
GetPitch() const | 每行位元組數(stride) | |
GetBits(int line=0) const | 取得指定行起始指標 | |
GetBits(int x, int y) const | 取得像素 (x,y) 指標 | |
IsInside(int x, int y) const | 座標是否在圖像範圍內 | |
Width() / Height() | 寬/高 | |
Create(w, h, bits) | 建立空白圖像 | |
CopyPalette(dest, src) | ≤8bit 圖像調色盤拷貝 |
演算法庫透過單一進入點 SinglePixelProcessProc 遍歷像素並委派處理邏輯。使用者必須在自訂類別中加入此方法並貼上標準實作碼:
void FCObjImage::SinglePixelProcessProc(
FCSinglePixelProcessBase& PixelProcessor,
FCObjProgress* progress = NULL)
{
if (!PixelProcessor.ValidateColorBits(this)) return;
// 計算處理區域(支援部分區域處理)
RECT rcImg = {0, 0, Width(), Height()}, rcBlock, rcDest;
if (PixelProcessor.GetProcessRect() == NULL)
::CopyRect(&rcBlock, &rcImg);
else
::CopyRect(&rcBlock, PixelProcessor.GetProcessRect());
if (::IntersectRect(&rcDest, &rcImg, &rcBlock) == 0) return;
int nSpan = ColorBits() / 8; // 每像素位元組數
PixelProcessor.OnEnterProcess(this, rcDest);
for (int y = rcDest.top; y < rcDest.bottom; ++y) {
BYTE* pPixel = GetBits(rcDest.left, y);
for (int x = rcDest.left; x < rcDest.right; ++x, pPixel += nSpan) {
PixelProcessor.ProcessPixel(this, x, y, pPixel);
}
if (progress) progress->SetProgress(y * 100 / Height());
}
PixelProcessor.OnLeaveProcess(this);
}
此實作碼完成了:區域裁剪、像素遍歷、進度回呼、處理前後鉤子。演算法開發者只需繼承 FCSinglePixelProcessBase 並實作 ProcessPixel 即可。
庫內已包含常用單像素演算法,開箱即用:
FCPixelGrayscale — 灰階轉換FCPixelInvert — 反相/負片FCPixelBrightness — 亮度調整FCPixelContrast — 對比度調整FCPixelThreshold — 閾值二值化呼叫方式極簡潔:
myImage.SinglePixelProcessProc(FCPixelGrayscale());
myImage.SinglePixelProcessProc(FCPixelInvert());
FCObjProgress 為抽象介面,僅含 virtual void SetProgress(int percent)。使用者可實作對話框進度條、Console 輸出、或無操作空實作。演算法執行期間每行像素處理完畢自動回呼,適合長時間運算的 UI 回應。
FCObjImage 派生自訂類別(如 CMyImage)SinglePixelProcessProc 標準實作碼PixelProcessor.cpp,#include "MyImage.h"CMyImage 實例套用所有內建/自訂演算法繼承 FCSinglePixelProcessBase,實作:
class MyCustomFilter : public FCSinglePixelProcessBase {
public:
bool ValidateColorBits(const FCObjImage* img) override {
return img->ColorBits() == 24; // 僅支援 24-bit
}
void ProcessPixel(FCObjImage* img, int x, int y, BYTE* pPixel) override {
// pPixel[0]=B, [1]=G, [2]=R (視實際格式)
BYTE avg = (pPixel[0] + pPixel[1] + pPixel[2]) / 3;
pPixel[0] = pPixel[1] = pPixel[2] = avg; // 簡易灰階
}
};
FCNeighborhoodProcessBase 介面。本庫展示了「介面導向設計」在圖像處理領域的實務價值:將演算法從資料結構中解耦,使既有專案零成本引入新演算法,也讓演算法開發者專注於核心邏輯而不受儲存格式束縛。完整原始碼與範例專案請參考附件。