самый эффективный метод для заполнения черной рамки вокруг изображения в переполнении стека

У меня есть изображение 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) вокруг изображения? Границу можно настроить на любую ширину.

Единственное, что я могу придумать, это в значительной степени ручная вставка строк и столбцов, которая становится очень утомительно длинным фрагментом кода.

извините, но библиотеки не то, что я ищу здесь

2

Решение

Вот самый читаемый способ, который я могу придумать, который также достаточно эффективен. Скажем, у вас есть изображение размеров Width от Height и желаемые поля Left, Right, Top, а также Bottom, Выделить буфер Width + Left + Right от Height + Top + Bottom заполнены нулями. В C ++ вы можете использовать один из удобных 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) {
// ...
}
1

Другие решения

Вы не упомянули платформу, но если вы на x86, Интегрированные производительные примитивы Intel (IPP) библиотека, в частности библиотека обработки изображений, добавит границы вокруг изображений выбранного цвета, либо на месте на существующем изображении, либо как часть копирования, изменения размера или нескольких других операций. И это чрезвычайно эффективный код.

3

Если вы уже используете библиотеку обработки изображений (Intel Performance Primitives, ImageMagick, Windows и т. Д.), Найдите существующую функцию, которая уже делает это. Реализация библиотеки, вероятно, будет быстрее, если авторы потрудились использовать инструкции MMX или SSE.

В противном случае, вы можете свернуть свое собственное решение, похожее на решение Эд С. Вот эскиз. Возможны дополнительные микрооптимизации, такие как сокращение количества вызовов 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);
}
2

Вы смотрели на какие-либо готовые библиотеки обработки изображений? Я использовал ImageMagick в прошлом — не самая простая вещь для установки, но она может многое сделать, как только она заработает. В том числе именно то, что вы хотите.

И если вам действительно нужно, чтобы ваша программа выполняла манипуляции с изображениями, это открытый исходный код. Хотя мы говорим «более 400 000 строк кода на C», вы, вероятно, захотите не касаться этого, если сможете избежать этого.

Надеюсь, это поможет!

0

Одно из соображений заключается в том, что результирующее изображение должно быть больше исходного, если только граница не перезаписывает оригинал. Последний случай просто включает в себя перезапись рассматриваемых пикселей, однако для случая «большего вывода» потребуется сначала выделить место для нового изображения.
После того, как вы выделите новый (вероятно, через какую-то библиотеку, которая генерирует соответствующие заголовки), вам нужно будет либо скопировать старый построчно (чтобы учесть пробелы), использовать быстрый API, который копирует прямоугольные образцы, такие как bitblt. Или используйте библиотеку, которая делает то же самое. Метод будет зависеть от самого формата изображения; просто bits[width*height-1] = {0}; форматы, такие как растровые изображения, будут работать с построчными memcpy или bit blt, но сжатые форматы, такие как pngs, могут нуждаться в библиотеке, которая может интерпретировать структуры данных. Если в вашей среде уже есть библиотеки (например, MSVS или Qt), вы можете просто использовать это. Но если это не вариант, вы можете просто использовать стороннюю библиотеку, подобную рекомендованной другими авторами.

0

Итак … Я не собираюсь предлагать использовать библиотеку для чего-то такого простого. Если вам нужно выполнять более сложные операции, в будущем обязательно посмотрите на это, но нарисуйте границу? Ни за что.

Это какой-то код, который у меня есть. Он рисует черный прямоугольник в заданном месте. Вы можете легко изменить его только на цвет по краям, если хотите. Обратите внимание, что это предполагает 24-битное изображение.

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
}
}
-1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector