具有通用uint8_t数据存储的图像类的迭代器
Iterator ofor an image class with generic uint8_t data storage
我有一个图像类,可以存储任何深度+任何精度(例如浮点、双精度)像素。我的数据存储在std::vector<uint8_t> m_pixels;
中,然后我根据通道数量和精度(以字节为单位)对像素进行迭代,即,为了迭代RGB浮动图像中的所有像素,我会进行
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);
...
}
有没有什么方法可以摆脱这种情况,或者让它成为一个更简单的代码,而不必总是依赖于在图像上迭代的链式if?
假设Image是一个模板结构,其中定义了迭代器类型:
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.使图像类本身成为模板
并提供它们之间的分配/转换
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
}
[edit]re"
我不能将其作为模板图像类,因为我需要从任何深度和任何像素数的文件中导入图像":
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.使迭代器类型不可知
即迭代器不是模板化的,而是在可以处理所有不同像素格式的"Pixel"类型上进行迭代。
理想情况下,迭代器将实现像素格式转换:
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位RGBA与ABGR),这可能会成为一个问题
在内部循环中使这种转换高效可能并非易事。
- 如何将图像传入C++可执行文件并将输出图像存储在新目录中?
- 存储将单个查询图像与多个图像的列表匹配的关键点索引
- 如何将捕获的图像存储在OpenCV中(将图片保存到计算机)
- 如何将多个图像存储到多个矩阵中
- 存储在矢量中的图像都是相同的
- 如何创建矩阵的矢量来存储大量的图像
- 对整个垫子图像进行排序并在 OpenCV 中存储索引
- 将图像存储在垫子矢量中
- 获取存储在矩阵中的图像 ROI 的平均 R、G 和 B
- 如何以最佳方式将高分辨率图像数据存储在无符号字符*中C++
- 如何将来自不同图像的多个描述符存储在C++和OpenCV中的向量向量中
- 为 ppm/pgm 图像数据创建存储
- 从数据库中以 blob 数据类型形式存储的原始图像数据中检索 CImage 对象
- OpenCV代码将存储在列表中的描述符与新的图像描述符进行比较
- 如何将图像中的每个像素作为16位索引存储到颜色表中
- 存储矢量的精确内存图像
- 如何将图像存储为 1*n 浮点向量
- 当传递给对象时,SDL_Surface在内存中存储图像的新实例,还是指向传递给它的图像?
- 如何用Ximea在c++中存储图像
- 使用c++ API在HDF5文件中存储图像