首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

通用圖像演算法擴充庫:以策略模式解耦圖像資料結構與處理演算法

     編輯:關於VC++

傳統圖像處理庫通常將圖像資料結構(像素儲存、色彩空間、幾何屬性)與演算法(濾波、幾何變換、色彩調整)綁定在同一個類別體系中,導致擴充新演算法需修改核心類別、或難以套用至既有專案的自訂圖像類別。本文介紹一個「通用圖像演算法擴充庫」,採用策略模式與非侵入式介面設計,僅提供演算法封裝與進度回呼,圖像物件本身由使用者自行定義,理論上可整合任何 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

演算法庫透過單一進入點 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 回應。

整合既有專案步驟總覽

  1. 從 FCObjImage 派生自訂類別(如 CMyImage)
  2. 實作上表所有介面方法(多為轉呼既有成員)
  3. 加入 SinglePixelProcessProc 標準實作碼
  4. 修改庫內 PixelProcessor.cpp,#include "MyImage.h"
  5. 即可對 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 介面。
  • 執行緒安全:庫本身無狀態,若多執行緒同時處理同一圖像實例,需由呼叫端同步。

總結

本庫展示了「介面導向設計」在圖像處理領域的實務價值:將演算法從資料結構中解耦,使既有專案零成本引入新演算法,也讓演算法開發者專注於核心邏輯而不受儲存格式束縛。完整原始碼與範例專案請參考附件。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved