2016-07-21 55 views
1

我有一個圖像類,可以存儲任何深度+任何精度(如浮動,雙)像素。我的數據被存儲在一個std::vector<uint8_t> m_pixels;,然後我遍歷基於信道和精度(以字節爲單位),即數量的像素,遍歷所有像素的RGB浮動圖像我會做迭代器或圖像類與通用uint8_t數據存儲

float *ptr = reinterpret_cast<float*>(m_pixels.data()); 
int stride = numberOfChannels * sizeof(float); 
for (int i = 0; i < imgWidth * imgHeight; i += stride) { 
    float& pixel = ptr[i]; 
    ... 
} 

(請現在忘記優化代碼,例如移動指針等)

現在我試圖創建一個基於std::iterator的迭代器。可以稱之爲ImageIter。我有以下問題:如果我有這樣的一個模板化的迭代,我會一直有這樣的代碼:

if (image.isFloat()) { 
    ImageIter<float> i(image); 
    ... 
} else if (image.isDouble()) { 
    ImageIter<double> i(image); 
    ... 
} 

有沒有辦法擺脫這種或使之成爲一個更簡單的代碼,而不必總是依賴於鏈接,如果對迭代圖像?

+0

無法使用圖像類包含模板參數及其迭代器的類型和類型嗎?例如'圖片 :: iterator' –

+0

@ W.F。你的意思是typedef?但是,無論如何,我怎樣才能做到這一點? – manatttta

回答

1

假設圖像是一個模板結構中都定義了迭代器類型:

template <class T> 
struct Image { 
    using iterator = ImageIter<T>; 
    //... 
}; 

如果你想迭代一般只使用類似模板函數:

template <class T> 
void iterateIf(const Image<T> &cit) { 
    // do sth if image has T 
} 

int main() { 
    Image<float> floatImage; 
    iterateIf(floatImage); //will execute templated iterateIf 
} 

現在如果你想做一些特定的操作只是當圖像包含雙打時創建iterateIf過載:

template <class T> 
void iterateIf(const Image<T> &cit) { 
    // do sth if image has Ts 
} 

void iterateIf(const Image<double> &cid) { 
    // do something only when parameter is Image<double> 
} 

int main() { 
    Image<float> floatImage; 
    iterateIf(floatImage); //will execute templated iterateIf 
    Image<double> doubleImage; 
    iterateIf(doubleImage); //will execute iterateIf(const Image<double>&) 
} 
1

我會反對這個設計。

違反最少驚喜的原則:你的圖像類是元素類型不可知的,但迭代器不是。

使用不同的選項,所有的缺點:

1.使圖像類本身就是一個模板

...並提供轉讓/他們

template <typename TElement> class Image 
{ 
    public: 
    ... 
    template <typename TOtherElement> 
    Image(Image<TotherElement const & rhs); 
    ... 
}; 

這之間的轉換將if (image.is(...))上移一級。不一定更好,但不太令人驚訝(以一種好的方式)。

您可以實現對所有這些的頂部圖像處理共享接口:

class IImageManipulation 
{ 
    public: 
    virtual void FlipH() = 0; 
    virtual void FlipV() = 0; 
    virtual void Rotate(float angleDegrees) = 0; 
    ... 
    virtual void ~IImageManipulation() {} 
}; 

template <typename TElement> 
class Image : public IImageManipulation 
{ 
    // ... also implement the abstract methods 
} 

[編輯]重新
我不能讓這個模板圖像類,因爲我需要導入圖像在任何深度的文件和任意數量的像素」

unique_ptr<IImageManipulation> LoadImage(....) 
{ 
    // inspect stream what depth and pixel format you use 
    .. 
    // create instance 
    unique_ptr<IImageManipulation> img = CreateImage(pixeltype); 

    // ... and load 
    img->Load(file); 
} 

// Image factory function: 
unique_ptr<IImgManipulation> CreateImage(PixelType type) 
{ 
    switch (pixeltype) 
    { 
    case ptFloat: return unique_ptr<IImageManipulation>(new Image<float>()); 
    ... 
    } 
} 

您的容器將存儲unique_ptr<IImageManipulation>

這個想法是將所有通用圖像操作移動到界面。 這是而不是適用於像素級別的操作,需要在Image模板中實現或使用該模板。但是,對於圖像級別的操作,這是很好的。

2.進行迭代器類型不可知

即迭代未模板化,但在一個「像素」類型,它可以處理所有不同的像素格式進行迭代。

理想的情況下,迭代器將實現像素格式轉換:

Image imgf = MakeImage<float>(...); // an image storing floats 
for(Image::iterator it = imgf.begin(); ...) 
{ 
    Pixel & p = *it; // type of the iterator elements 

    float f = p.asFloat(); // read as float 
    int i = p.asInt32(); // read as int, convert in the fly 

    p = Pixel.FromRGB(17, 23, 432); // set as int, convert on the fly 
    p = Pixel.FromFloat(0.23); 
} 

請注意,轉換可製成隱含的,但如果你有不同的像素格式,具有不同的基本類型,這可能是一個問題(例如,32 bit RGBA vs. ABGR)

在內部循環中進行這種轉換效率可能不是微不足道的。

+0

我無法將其作爲模板化的圖像類,因爲我需要從任意深度和任意數量的像素中的文件導入圖像,並將它們存儲在全局容器中(即使它們具有不同類型)。 我只是需要一個優雅的方式來創建迭代器 – manatttta

+0

@manatttta所以你只需要一種方法來迭代你的圖像使用給定的迭代器類型?但在這種情況下,你在什麼基礎上回答圖像'isFloat()'? –

+0

@ W.F。對不起,我不明白這個問題 – manatttta