我有一个 RGB 图像,这样:
Img[3*(row*imgWidth+column)+0], //R
Img[3*(row*imgWidth+column)+1], //G
Img[3*(row*imgWidth+column)+2] //B
表示每个 RGB 的每个像素的强度值。什么是在图像周围填充 0(0-255 比例)边框的干净方法?边框可以调整为任意宽度。
我唯一能想到的就是手动插入行和列,这变成了一段非常冗长的代码。
对不起,但图书馆不是我在这里寻找的
我有一个 RGB 图像,这样:
Img[3*(row*imgWidth+column)+0], //R
Img[3*(row*imgWidth+column)+1], //G
Img[3*(row*imgWidth+column)+2] //B
表示每个 RGB 的每个像素的强度值。什么是在图像周围填充 0(0-255 比例)边框的干净方法?边框可以调整为任意宽度。
我唯一能想到的就是手动插入行和列,这变成了一段非常冗长的代码。
对不起,但图书馆不是我在这里寻找的
您还没有提到该平台,但如果您使用的是 x86,英特尔的集成性能基元 (IPP)库,特别是其图像处理库,将在所选颜色的图像周围添加边框,或者在现有图像上就地,或作为复制、调整大小或其他几个操作的一部分。这是非常高效的代码。
这是我能想到的最易读的方式,这也是相当有效的。假设您有一个尺寸Width
为、、和Height
的所需边距的图像。分配一个用零填充的缓冲区。在 C++ 中,您可以使用一种方便的构造函数:Left
Right
Top
Bottom
Width + Left + Right
Height + Top + Bottom
std::vector
const auto Channels = 3;
const auto TargetWidth = Width + Left + Right;
const auto TargetHeight = Height + Top + Bottom;
std::vector<uint8_t> target(TargetWidth * TargetHeight * Channels);
C 函数calloc()
也是一个选项。接下来,将源图像中的每一行复制到目标图像,从垂直偏移量Top
和水平偏移量开始Left
。用于std::copy()
复制行,并以行优先顺序运行外部循环以避免缓存未命中:
for (int y = 0; y < Height; ++y) {
const auto* const source_row = &source[y * Width * Channels];
auto* const target_row = &target[(y + Top) * TargetWidth * Channels + Left];
std::copy(source_row, source_row + Width * Channels, target_row);
}
如果您可以使用 32 位 RGB0 或 RGBA 而不是 24 位 RGB,您可能会看到更快的复制,这要归功于更一致的对齐方式,std::copy()
或者memcpy()
已经得到了很好的优化。如果您可以使用OpenMP,您还可以尝试并行化循环:
#pragma omp parallel for
for (int y = 0; y < Height; ++y) {
// ...
}
如果您已经在使用图像处理库(Intel Performance Primitives、ImageMagick、Windows 等),请查找已经执行此操作的现有函数。如果作者不厌其烦地使用 MMX 或 SSE 指令,库的实现可能会更快。
如果做不到这一点,您可以使用类似于 Ed S. 的解决方案自行开发。这是一个草图。可以进行额外的微优化,例如将 memset 调用的数量减半。
unsigned char* padWithBlack(const unsigned char* in,
int inWidth, int inHeight,
int thickness)
{
unsigned char* out = malloc((inWidth + thickness * 2) *
(inHeight + thickness * 2) * 3);
// top border
int topOrBottomOutBytes = (inWidth + thickness * 2) * thickness * 3;
memset(out, 0, topOrBottomOutBytes);
// middle section
unsigned char* inRow = in;
unsigned char* outRow = out + topOrBottomOutBytes;
for (int inY = 0; inY < inHeight; inY++) {
// left border
memset(outRow, 0, thickness * 3);
outRow += thickness * 3;
// center section
memcpy(outRow, inRow, inWidth * 3);
outRow += inWidth * 3;
inRow += inWidth * 3;
// right border
memset(outRow, 0, thickness * 3);
outRow += thickness * 3;
}
// bottom border
memset(out, 0, topOrBottomOutBytes);
}
你看过任何预先构建的图像处理库吗?我过去使用过ImageMagick - 这不是最容易安装的东西,但一旦你让它工作,它可以做很多事情。包括你想要的。
如果你真的需要让你的程序进行图像处理,它是开源的。虽然我们说的是“超过 400,000 行 C 代码”,但如果可以避免的话,您可能希望避免接触它。
希望有帮助!
一种考虑是生成的图像必须大于源图像,除非边框覆盖了原始图像。后一种情况只涉及覆盖有问题的像素,但是“更大的输出”情况将需要首先为新图像分配空间。一旦分配了新的(可能通过一些生成适当标题的库),您需要逐行 memcopy 旧的(以解决差距),使用复制矩形样本的快速 api,如 bitblt ,或使用本质上相同的库。该方法将取决于图像格式本身;简单的bits[width*height-1] = {0};
位图等格式将与逐行 memcpy 或 bit blt 一起使用,但像 pngs 这样的压缩格式可能需要一个可以解释数据结构的库。如果您的环境已经有这些库(例如 MSVS 或 Qt),您也可以使用它。但如果这不是一个选项,您可以只使用其他海报推荐的第三方库。
所以...我不会建议将库用于如此简单的事情。如果你以后需要进行更高级的操作肯定会考虑它,但是画一个边框?没门。
这是我周围的一些代码。它在给定位置绘制一个黑色矩形。如果您愿意,您可以轻松地将其更改为仅在边缘着色。请注意,它假定图像为 24 bpp。
void WriteDebugImage( const unsigned char* inImageBuf, int inImageWidth, int inImageHeight, int left, int top, int right, int bottom, unsigned char* outImage )
{
// copy the old image into the new one
memcpy( outImage, inImageBuf, inImageWidth * inImageHeight * 3 );
for( int x = left; x <= right; ++x )
{
outImage[3 * top * inImageWidth + 3 * x] = 0; //Top Edge
outImage[3 * top * inImageWidth + 3 * x + 1] = 0; //Top Edge
outImage[3 * top * inImageWidth + 3 * x + 2] = 0; //Top Edge
outImage[3 * bottom * inImageWidth + 3 * x] = 0; //Bottom Edge
outImage[3 * bottom * inImageWidth + 3 * x + 1] = 0; //Bottom Edge
outImage[3 * bottom * inImageWidth + 3 * x + 2] = 0; //Bottom Edge
}
for (int y = top; y <= bottom; ++y)
{
outImage[3 * y * inImageWidth + 3 * left] = 0; //Left Edge
outImage[3 * y * inImageWidth + 3 * left + 1] = 0; //Left Edge
outImage[3 * y * inImageWidth + 3 * left + 2] = 0; //Left Edge
outImage[3 * y * inImageWidth + 3 * right] = 0; //Right Edge
outImage[3 * y * inImageWidth + 3 * right + 1] = 0; //Right Edge
outImage[3 * y * inImageWidth + 3 * right + 2] = 0; //Right Edge
}
}