алгоритм масштабирования изображения .bmp с использованием C ++ и только заголовков iostream и stdio?

В настоящее время я делаю свое первое программирование на C ++, и моя цель — масштабировать растровое изображение, используя только основные заголовки ввода-вывода.

Я использовал http://en.wikipedia.org/wiki/BMP_file_format#DIB_header_.28bitmap_information_header.29 как мой справочник по поиску информации заголовка.

Моя проблема заключается в создании алгоритма для увеличения изображения с точки зрения добавления отдельных пикселей.
Я сделал серию циклов for, которые комментируются (они используют информацию заголовка, чтобы определить, сколько нужно запустить), но я понятия не имею, что делать дальше с точки зрения манипулирования фактическими пикселями, это где мне нужна помощь

Когда я запускаю программу, создается новый файл BMP (называемый Image2), однако он поврежден и имеет размер 1 КБ (скорее всего потому, что программа не завершена).

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

 int main()
{

FILE* pFile = NULL;
FILE* pFile2 = NULL;//Open Image.bmp (In directory) as read binary
pFile = fopen("Image.bmp, "rb");
//Scan through the program and set to send.
fseek (pFile, 0, SEEK_END);
//Read file data
int fileData = ftell (pFile);
//set back to start of char pointer
rewind (pFile);//Create a Char Filebuffer, this will be where data is viewed.
char* FileBuffer = new char[fileData];
//Read pFile into Filebuffer
fread(FileBuffer, fileData, 1, pFile);

//Read out BMP Header Data and Cast to Int
int ImageSize = *(int*)&FileBuffer[2];
int ImageOffset = *(int*)&FileBuffer[10]; //ImageOffset = Image Header Size
int ImageHeight = *(int*)&FileBuffer[18];
int ImageWidth = *(int*)&FileBuffer[20];
int BitsPerPixel = *(int*)&FileBuffer[24];

//Create a New Buffer that starts off at Pixel Data
char* NewFileBuffer = FileBuffer + ImageOffset;std::cout << "Enter the amount of times you want to scale the image by." << std::endl;
std::cin >> ScaleValue;
std::cout << "\n";

//Create New Image row/height/size variables
int RowSizeOld = (BitsPerPixel * ImageWidth +31)/32 * 4;
int RowSizeNew = (BitsPerPixel *(ImageWidth * ScaleValue) + 31) / 32 * 4;
int NewImageSize = ImageOffset + (RowSizeNew * (ScaleValue * ImageHeight) );
int NewImageHeight = ImageHeight * ScaleValue;
int NewImageWidth = ImageWidth * ScaleValue;// These ints define the colour values for RGB and Padding
int r = ImageOffset + 1;
int g = ImageOffset + 2;
int b= ImageOffset + 3;
int p = ImageOffset + 4;//Rescale Image here, for (Newfile buffer [0])
// This for loop figures out how many times the newHeight variable must iterate
for (int newHeight = 0 ; newHeight < NewImageHeight ; newHeight++)
{
//This line scales up the amount of rows in terms of scale value
for(int doubleLine = 0 ; doubleLine < ScaleValue ; doubleLine++)
{
//This for loop then figures out the width of the new image in pixels as an int value
for (int newWidth = 0 ; newWidth < NewImageWidth ; newWidth++)
{
//This loop figures out how many times you need to increase the pixel density (for each pixel)
for (int pixelMultiplier = 0 ; pixelMultiplier < ScaleValue ; pixelMultiplier++)
{

//Move pixel data around to scale image (This is where I'm having trouble)

}
}}}//Create a new File pointer, add image name + bmp string
FILE* pFile2;
pFile2 = fopen("Image2.bmp", "wb");
fwrite(NewFileBuffer, (NewImageSize + ImageOffset), sizeof(char) , pFile2);

return 0;
}

Это мой первый пост на SE, поэтому я приношу свои извинения, если формат кода немного коренастый или вопрос сложный для понимания (я прочитал форум и урезал свой код, чтобы сделать его более читабельным)

3

Решение

Выполнение простого ближайшего повторного сэмплирования, вероятно, является самым простым способом сделать это. Для этого вы просто рассчитываете соотношение между новым и старым размерами следующим образом:

float xStep = (float)oldWidth / (float)newWidth;
float yStep = (float)oldHeight / (float)newHeight;

Теперь вы знаете, что, когда вы шагаете на 1 пиксель в направлении x для нового изображения, вы добавляете пиксели «xStep» к старому изображению. Затем вы округляете позицию сэмплирования до ближайшего целочисленного местоположения, выбираете ее из старого изображения и записываете в новое! Теперь у вас есть простое изображение с повторной выборкой.

Для еще лучших результатов вы можете Билинейный фильтр как вы повторно образца. Это очень простая 2D линейная интерполяция.

Чтобы дать вам одномерный пример фильтрации значений с плавающей запятой, вы должны написать некоторый код, подобный следующему:

for( float x = 0, int xOut = 0; x += xStep, xOut++; xOut < newWidth; )
{
const float sample0  = old1D[std::floor( x )];
const float sample1  = old1D[std::ceil( x )];

const float t        = x - std::floor( x );

const float sample   = sample0 + ((sample1 - sample0) * t);

new1D[xOut] = sample;
}

Конечно, я не забочусь о крайних случаях, но заботу о них и расширение до 2D следует оставить в качестве упражнения в случае назначения.

Также стоит отметить, что этот вид фильтрации будет выглядеть немного неправильно, если вы масштабируете изображение более чем в 2 раза из-за того, что вы по-прежнему полностью пересекаете пиксели. Это обычно решается путем предварительной фильтрации изображения в набор изображений половинной ширины и высоты на каждом шаге. Это известно как MIP-отображение.

Удачи!

1

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

Идея состоит в том, чтобы умножить существующие пиксели, а не добавлять полностью новые.
Для положительного масштабирования вы можете создать новое растровое изображение, в x раз больше старого.
Затем заполните новое растровое изображение старыми пикселями и дубликатами.

Схема выглядит следующим образом:

| O1 | d1 | o2 | d2 |
| D1 | d1 | d2 | d2 |

Где o1 — старый пиксель, а d1 — его дубликат.

Таким образом, вам придется просмотреть все пиксели и определить, как часто и где они будут заполнены в новом растровом изображении.

1

По вопросам рекламы [email protected]