Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Разбор BMP файл

57K
04 января 2011 года
sqwerty
34 / / 04.01.2011
Добрый день!

Я вот хочу обработать BMP файл. Структуру BMP знаю прекрасно, но у меня не получается обрезать BMP по контору, да и сместить как-то надо бы....:)

Спасибо,
с уважением sqwerty!

P.S. Если интересно, то могу показать код по разборку BMP.
278
04 января 2011 года
Alexander92
1.1K / / 04.08.2008
Ну вы приведите код, как вы пытаетесь обрезать, посмотрим... :)
57K
04 января 2011 года
sqwerty
34 / / 04.01.2011
typedef struct
{
__int8 bfType[2];
__int32 bfSize;
__int16 bfReserved1;
__int16 bfReserved2;
__int16 bfOffBits;
} BITMAPFILEHEADER;

typedef struct
{
__int32 biSize;
__int32 biWidth;
__int32 biHeight;
__int16 biPlanes;
__int16 biBitCount;
__int32 biCompression;
__int32 biSizeImage;
__int32 biXPelsPerMeter;
__int32 biYPelsPerMeter;
__int32 biClrUsed;
__int32 biClrImportant;
} BITMAPINFOHEADER;

// Собственно обрез по контуру
__int8* crop(__int8* rastr, int height, int width, int nb)
{
int i=0,j=0, k=0;
__int8 tempw=0, temph=0;
int height_board=0,height_board1=0, he=0, wi=0;
height_board=height/2;
int s = height*width*3, ind=0;
unsigned char *ff = new unsigned char;
for(j=1200;j<width*3;j++)
{
for(i=0,k=height-1;i<height_board;i++,k--)
{
ff[ind++]=(*(rastr+i*(width*3+nb)+j));
// *(rastr+i*(width*3+nb)+j)=255;
ff[ind++]=(*(rastr+k*(width*3+nb)+j));
//*(rastr+k*(width*3+nb)+j)=255;
}
}
for(j=0;j<width*3-1200;j++)
{
for(i=0,k=height-1;i<height_board;i++,k--)
{
ff[ind++]=(*(rastr+i*(width*3+nb)+j));
// *(rastr+i*(width*3+nb)+j)=0;
ff[ind++]=(*(rastr+k*(width*3+nb)+j));
//*(rastr+k*(width*3+nb)+j)=0;
}
}
for(j=0;j<width*3;j++)
{
for(i=0,k=0;i<height_board, k<50;i++,k++)
{
tempw=(*(rastr+i*(width*3+nb)+j));
*(rastr+i*(width*3+nb)+j)=0;
temph=(*(rastr+k*(width*3+nb)+j));
*(rastr+k*(width*3+nb)+j)=0;
}
for(i=height-1,k=height-1; i>height_board;i--,k--)
{
if(k>200){
tempw=(*(rastr+i*(width*3+nb)+j));
*(rastr+i*(width*3+nb)+j)=0;
temph=(*(rastr+k*(width*3+nb)+j));
*(rastr+k*(width*3+nb)+j)=0;
}
else{
tempw=(*(rastr+i*(width*3+nb)+j));
*(rastr+i*(width*3+nb)+j)=tempw;
temph=(*(rastr+k*(width*3+nb)+j));
*(rastr+k*(width*3+nb)+j)=temph;
}
}
}
return rastr;
}
57K
04 января 2011 года
sqwerty
34 / / 04.01.2011
но у меня стирается растр и не обрезается. Как обрезать?
278
04 января 2011 года
Alexander92
1.1K / / 04.08.2008
sqwerty, может быть, я неправильно понял вашу задачу (хотя с трудом представляю, что здесь можно не понять :)), но зачем вы это делаете так сложно? Фактически, у вас есть массив байтов rastr, вам нужно из него вырезать некоторый подмассив, я правильно понял? Почему бы вам не посчитать длину/ширину изображения, перевести растр в стандартный двумерный массив и просто вырезать интересующую вас часть?
297
04 января 2011 года
koodeer
1.2K / / 02.05.2009
Для работы с изображениями удобно использовать GDI+.
Чтобы вырезать часть изображения, можно использовать Method Clone.
Полезная ссылка: http://rsdn.ru/summary/626.xml
278
04 января 2011 года
Alexander92
1.1K / / 04.08.2008
koodeer, насколько я понимаю, речь идет о работе непосредственно с растром. Библиотеки уровня GDI+ скрывают от программиста действия такого низкого уровня.
57K
04 января 2011 года
sqwerty
34 / / 04.01.2011
Alexander92, я пробовал вырезать нужный контур в некий подмассив, но при записи в новый файл записывается неправильно.
или же необходимо менять и структуру BMP вместе с остальными..?, т.е. не структуру, а смещение я имею ввиду...
вот как определяю растр:
__int8* rastr=NULL;
rastr=(__int8*)malloc(ihead.biSizeImage);
//Чтение растра
fread(rastr,ihead.biSizeImage,1,bmp_src);
rastr = crop(rastr,ihead.biHeight,ihead.biWidth,nb);
278
04 января 2011 года
Alexander92
1.1K / / 04.08.2008
А вы переписываете заголовок с учетом изменившегося размера? Потом, такой вопрос - вы смотрите чем-нибудь типа WinHex'а то, что вышло?
57K
04 января 2011 года
sqwerty
34 / / 04.01.2011
об этом я и хотел бы узнать, что именно меняется в заголовке влияющее на размер?
да, я смотрю с помощью rawviewer что получилось на выходе. на вход подаю YV12.

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

может в этом и всё дело...?
278
04 января 2011 года
Alexander92
1.1K / / 04.08.2008
Цитата: sqwerty
я тупо переписываю заголовок в новый файл, а вообще-то я дважды записываю матрицу в файл, сначала заголовок и сама матрица, патом растр записываю...



Вот в этом ваша проблема. Почитайте внимательно спецификацию BMP-формата. В BMP-файле первые два байта - это "BM", после этого идет размер файла в байтах. После этого 4 байта нули. Потом - размер описания формата в байтах, потом само описание, а потом растр. Скорее всего, эта последовательность у вас где-то нарушается.

57K
04 января 2011 года
sqwerty
34 / / 04.01.2011
возможно, я попробую переопределить структуру файла....
57K
06 января 2011 года
sqwerty
34 / / 04.01.2011
у меня никак не получается записать BMP в новый файл правильно, может кто подскажет каков порядок и в чем прикол...?
342
06 января 2011 года
Yos
209 / / 21.06.2003
Ну для начала надо знать из чего и во что вы переводите, так как файлы ВМР имеют очень интересную структуру, и не смотря на то что утверждаете что знаете структуру, вы ее не знаете и делаете элементарнейшие ошибки...

1. данные растра выровняны DWORD в строке не зависимо от формата, те это совсем не значит что в DWORD именно одна точка,тем более что это большая редкость.
2. как вы проверили что там нет RLE...
3. и как можно структуры просто копировать...

Так как сегодня Рождество, вот вам мой подарок, преобразование любого файла в ВМР с альфа каналом (DWORD - один пиксел):
Код:
//*************************************************************
//**
//**
//**
//*************************************************************
void TFrame::LoadAlphaImage(void)
{
 //****
 HANDLE                 token;
 GdiplusStartupInput    in;
 GdiplusStartupOutput   out;
 
 BITMAP                 bitmap;
 BITMAPINFO             bitmapinfo;

 GpImage              * pImage = NULL;
 GpGraphics           * pGraphics;
 GpStatus               status = Ok;
 
 CHAR                   value[MAX_TEXT_SIZE];

 HDC                    hdc;
 HDC                    memdc;

 //
 GdiplusStartup((ULONG_PTR *)&token,&in,&out);

 // вообщем можно загрузить любой файлец, не только ВМР
 XString::SystemToUnicode("alpha.png",(LPWORD)value);
 status = GdipLoadImageFromFile((WCHAR *)value,&pImage);
 if( status == Ok )
 {
    //
    GdipGetImageWidth(pImage,(UINT *)&ImageWidth);
    GdipGetImageHeight(pImage,(UINT *)&ImageHeight);

    // создаем эталонный контекст
    hdc = CreateDC("DISPLAY",NULL,NULL,NULL);
    // создаем временный контекст для исходного изображения
    memdc = CreateCompatibleDC(hdc);
   
    // создаем совместимое изображение
    memset((void *)&bitmapinfo,0,sizeof(BITMAPINFO));
    bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bitmapinfo.bmiHeader.biWidth = ImageWidth;
    bitmapinfo.bmiHeader.biHeight = ImageHeight;
    bitmapinfo.bmiHeader.biPlanes = 1;
    bitmapinfo.bmiHeader.biBitCount = 32;
    bitmapinfo.bmiHeader.biCompression = BI_RGB;
    bitmapinfo.bmiHeader.biSizeImage = bitmapinfo.bmiHeader.biWidth * (bitmapinfo.bmiHeader.biBitCount / 8) * bitmapinfo.bmiHeader.biHeight;
    hWindowImage = CreateDIBSection(memdc,&bitmapinfo,DIB_RGB_COLORS,NULL,NULL,0);
   
    // выбираем изображение в контекст
    SelectObject(memdc,hWindowImage);
   
    //
    GdipCreateFromHDC(memdc,&pGraphics);
    GdipDrawImageRect(pGraphics,pImage,0,0,(REAL)ImageWidth,(REAL)ImageHeight);

    //
    GdipDisposeImage(pImage);
    GdipDeleteGraphics(pGraphics);

    // удаляем временные контексты
    DeleteDC(hdc);
    DeleteDC(memdc);
 }

 //
 GdiplusShutdown((ULONG_PTR)token);

 //****
 XMemory              * pFile;

 HICOLOR_RGB          * pData;
 BITMAPFILEHEADER     * pFileHeader;
 BITMAPINFOHEADER     * pInfoHeader;

 int                    width;
 int                    height;

 //
 pFile = new XMemory();
 if( pFile->Initialize() )
 {
    //
    if( pFile->SetSize(sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)) )
    {
        //
        GetImageBits(hWindowImage,&pData,&width,(int *)&height);
        pFile->AppendData((LPBYTE)pData,width*height*sizeof(HICOLOR_RGB));
        FreeImageBits(pData);

        //
        pFileHeader = (BITMAPFILEHEADER *)pFile->GetPointer();
        pInfoHeader = (BITMAPINFOHEADER *)pFile->GetPointer(sizeof(BITMAPFILEHEADER));

        //
        pFileHeader->bfType = 0x4D42;
        pFileHeader->bfSize = pFile->GetSize();
        pFileHeader->bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

        //
        pInfoHeader->biSize = sizeof(BITMAPINFOHEADER);
        pInfoHeader->biWidth = width;
        pInfoHeader->biHeight = height;
        pInfoHeader->biPlanes = 1;
        pInfoHeader->biBitCount = 32;
        pInfoHeader->biCompression = BI_RGB;
        pInfoHeader->biSizeImage = pFile->GetSize() - sizeof(BITMAPFILEHEADER) - sizeof(BITMAPINFOHEADER);
        pInfoHeader->biXPelsPerMeter = 72;
        pInfoHeader->biYPelsPerMeter = 72;
       
        //
        pFile->Save("alpha.bmp");
    }

    //
    pFile->Release();
 }
 
 //
 delete pFile;
}

//*************************************************************

typedef struct _HICOLOR_RGB
{
    union
    {
        // цельный цвет
        DWORD   Color;

        // составляющие
        struct
        {
            BYTE    B;
            BYTE    G;
            BYTE    R;
            BYTE    Alpha;

        } Layer;
    };

} HICOLOR_RGB, *PHICOLOR_RGB, *LPHICOLOR_RGB;

//*************************************************************
//**
//** Получить блок данных изображения
//**
//*************************************************************
BOOL XGraphics::GetImageBits(HBITMAP hImage, LPHICOLOR_RGB * pImageBits, int * pWidth, int * pHeight)
{
 //****
 HDC                hdc;
 HDC                sdc;
 
 BITMAP             bitmap;
 BITMAPINFO         bitmapinfo;
 
 BOOL               alloc = FALSE;

 // создаем эталонный контекст
 hdc = CreateDC("DISPLAY",NULL,NULL,NULL);
 // создаем временный контекст для исходного изображения
 sdc = CreateCompatibleDC(hdc);

 // определяем размеры исходного изображения
 GetObject(hImage,sizeof(BITMAP),&bitmap);

 // определяем структуру для получения данных изображения
 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
 bitmapinfo.bmiHeader.biWidth = bitmap.bmWidth;
 bitmapinfo.bmiHeader.biHeight = bitmap.bmHeight;
 bitmapinfo.bmiHeader.biPlanes = 1;
 bitmapinfo.bmiHeader.biBitCount = 32;
 bitmapinfo.bmiHeader.biCompression = BI_RGB;
 bitmapinfo.bmiHeader.biSizeImage = bitmap.bmWidth * sizeof(HICOLOR_RGB) * bitmap.bmHeight;
 bitmapinfo.bmiHeader.biXPelsPerMeter = 0;
 bitmapinfo.bmiHeader.biYPelsPerMeter = 0;
 bitmapinfo.bmiHeader.biClrUsed = 0;
 bitmapinfo.bmiHeader.biClrImportant = 0;

 // если блок данных отсутствует
 if( *(pImageBits) == NULL )
 {
    // выделяем память для данных
    *(pImageBits) = (LPHICOLOR_RGB)GlobalAlloc(GPTR,bitmapinfo.bmiHeader.biSizeImage);
   
    // выставляем признак выделения блока данных
    alloc = TRUE;
 }

 // если блок данных существует
 if( *(pImageBits) )
 {
    // получаем данные
    if( GetDIBits(sdc,hImage,0,bitmap.bmHeight,(LPVOID)*(pImageBits),&bitmapinfo,DIB_RGB_COLORS) )
    {
        // удаляем временные контексты
        DeleteDC(hdc);
        DeleteDC(sdc);

        // возвращаем размер изображения
        *(pWidth) = bitmap.bmWidth;
        *(pHeight) = bitmap.bmHeight;

        return TRUE;
    }

    // если память под данные выделяли
    if( alloc )
    {
        // освобождаем память
        GlobalFree(*(pImageBits));
        *(pImageBits) = NULL;
    }
 }

 // удаляем временные контексты
 DeleteDC(hdc);
 DeleteDC(sdc);

 return FALSE;
}

//*************************************************************
//**
//** Получить изображение на основании его данных
//**
//*************************************************************
BOOL XGraphics::SetImageBits(LPHICOLOR_RGB pImageBits, int width, int height, HBITMAP * pImage)
{
 //****
 HDC                hdc;
 HDC                sdc;
 
 BITMAPINFO         bitmapinfo;
 
 HBITMAP            hImage;

 // создаем эталонный контекст
 hdc = CreateDC("DISPLAY",NULL,NULL,NULL);

 // создаем временный контекст для исходного изображения
 sdc = CreateCompatibleDC(hdc);
 // создаем совместимое изображение
 hImage = CreateCompatibleBitmap(hdc,width,height);

 // определяем структуру для создания изображения
 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
 bitmapinfo.bmiHeader.biWidth = width;
 bitmapinfo.bmiHeader.biHeight = height;
 bitmapinfo.bmiHeader.biPlanes = 1;
 bitmapinfo.bmiHeader.biBitCount = 32;
 bitmapinfo.bmiHeader.biCompression = BI_RGB;
 bitmapinfo.bmiHeader.biSizeImage = width * sizeof(HICOLOR_RGB) * height;
 bitmapinfo.bmiHeader.biXPelsPerMeter = 0;
 bitmapinfo.bmiHeader.biYPelsPerMeter = 0;
 bitmapinfo.bmiHeader.biClrUsed = 0;
 bitmapinfo.bmiHeader.biClrImportant = 0;

 // создаем изображение
 if( SetDIBits(sdc,hImage,0,height,(LPVOID)pImageBits,&bitmapinfo,DIB_RGB_COLORS) )
 {
    // если изображение существует - удаляем его
    if( *(pImage) ) DeleteObject((HBITMAP)*(pImage));

    // возвращаем изображение
    *(pImage) = hImage;

    // удаляем временные контексты
    DeleteDC(hdc);
    DeleteDC(sdc);

    // возвращаем изображение
    return TRUE;
 }

 // удаляем временные контексты
 DeleteDC(hdc);
 DeleteDC(sdc);

 // удаляем изображение
 DeleteObject((HBITMAP)hImage);

 return FALSE;
}

//*************************************************************
//**
//** Освободить данные изображения
//**
//*************************************************************
BOOL XGraphics::FreeImageBits(LPHICOLOR_RGB pImageBits)
{
 // освобождаем память
 if( GlobalFree(pImageBits) ) return FALSE;
 return TRUE;
}


Вообщем остальное (типа XMemory) приводить смысла нет, так как вам важен принцип, а он тут изложен полностью...

Вам важен блок pData (растр в DWORD с которым можно работать) и заполнение полей заголовка перед сохранением...

PS кстати не забудьте, что строки растра идут снизу вверх...
342
07 января 2011 года
Yos
209 / / 21.06.2003
Кстати о работе с ВМР с альфаканалом - зачем вообще это нужно? Да как правило для вывода изображений с прозрачностью в контекст или (откуда мой ранее приведенный код написанный от нечего делать в качестве изучения материала) создание окон с разной степенью прозрачности по плоскости...

Делается это вот так, сначала создаем окно с:
 
Код:
// создаем окно
hWindow = CreateWindowEx(WS_EX_LAYERED,"TTestFrameClass",NULL,WS_POPUP,(GetSystemMetrics(SM_CXSCREEN)-ImageWidth)/2,(GetSystemMetrics(SM_CYSCREEN)-ImageHeight)/2,ImageWidth,ImageHeight,hParent,NULL,hApplicationInstance,NULL);


потом формируется вид окна в виде растра с требуемыми параметрами, делается SetImageBits и далее следующее:
Код:
//*************************************************************
//**
//** Полная перерисовка окна
//**
//*************************************************************
void TFrame::RepaintWindow(void)
{
 //****
 HDC            hdc;
 HDC            memdc;

 RECT           window;

 BLENDFUNCTION  Blend;
 POINT          Offset;
 POINT          WindowOffset;
 SIZE           WindowSize;

 // открываем контекст перерисовки
 hdc = GetDC(hWindow);
 // создаем копию совместимого контекста
 memdc = CreateCompatibleDC(hdc);

 // выбираем полученное изображение в качестве текущего для установки
 SelectObject(memdc,(HBITMAP)hWindowImage);

 // готовим данные для установки
 Blend.BlendOp = AC_SRC_OVER;
 Blend.SourceConstantAlpha = 255;
 Blend.AlphaFormat = AC_SRC_ALPHA;
 Blend.BlendFlags = 0;
 //
 Offset.x = 0;
 Offset.y = 0;
 //
 GetWindowRect(hWindow,&window);
 WindowOffset.x = window.left;
 WindowOffset.y = window.top;
 //
 WindowSize.cx = ImageWidth;
 WindowSize.cy = ImageHeight;
 
 // устанавливаем рабочее изображение
 UpdateLayeredWindow(hWindow,hdc,&WindowOffset,&WindowSize,memdc,&Offset,0,&Blend,ULW_ALPHA);

 // удаляем совместимый контекст
 DeleteDC(memdc);

 // закрываем контекст перерисовки
 ReleaseDC(hWindow,hdc);
}


Тем более в обоих случаях применения таскать в ресурсах PNG не удобно, а вот ВМР очень даже...

PS Кстати в таких окнах нет обработки WM_PAINT, по этому необходимо сначала рисовать ВМР в памяти а потом его устанавливать в качесте вида окна...

PPS Вообщем всех с Рождеством...
57K
07 января 2011 года
sqwerty
34 / / 04.01.2011
Повторяю задачу:
1. Прочитать и записать BMP в новый файл это понятно, но главная задача не в этом, а в том, что надо с начало матрицу (не заголовок) загрузить в буфер (в виде растра или как-то по другому), затем обрезать эту матрицу по контуру (при этом меняется размер файла, ширина, высота и горизонтальное/вертикальное разрешение, пиксел/м, оставшиеся мусор и пр.).
2. Обрезанную матрицу прикрепить к заголовку BMP и записать в новый файл.

Я пробовал тупо взять высоту и ширину, и сократить на нужный размер и переписать размер изображения (не файла). Получилось как-то искаженно, но я думаю это из-за горизонтальное/вертикальное разрешение, пиксел/м, т.к. они остались прежними и я не знаю как рассчитывать???

P.S. я работаю без API, так та будет более понятливее и чище код
342
08 января 2011 года
Yos
209 / / 21.06.2003
Цитата: sqwerty
Повторяю задачу:


Мне не надо ее повторять, так как то что вам надо и так уже описали далее, только сами ничего не поняли

Цитата: sqwerty
1. Прочитать и записать BMP в новый файл это понятно, но главная задача не в этом, а в том, что надо с начало матрицу (не заголовок) загрузить в буфер (в виде растра или как-то по другому), затем обрезать эту матрицу по контуру (при этом меняется размер файла, ширина, высота и горизонтальное/вертикальное разрешение, пиксел/м, оставшиеся мусор и пр.).
2. Обрезанную матрицу прикрепить к заголовку BMP и записать в новый файл.

Я пробовал тупо взять высоту и ширину, и сократить на нужный размер и переписать размер изображения (не файла). Получилось как-то искаженно, но я думаю это из-за горизонтальное/вертикальное разрешение, пиксел/м, т.к. они остались прежними и я не знаю как рассчитывать???


Попробуйте не "тупо"... Предварительно ознакомившись с теорией - Роджерс Д. Алгоритмические основы машинной графики, 1989 год. Особенно то что касается спрайтовой анимации и найдите хорошую книгу по форматам графических файлов.

Цитата: sqwerty
P.S. я работаю без API, так та будет более понятливее и чище код


код должен быть правильным а не "чистым"...

57K
08 января 2011 года
sqwerty
34 / / 04.01.2011
вот весь код с чем я работаю:

Код:
int pars_bmp2(char* f_src,char* f_dest)
{
   FILE *bmp_src,*bmp_dest;  //{ для чтения картинки }
   int res;        //{ код ошибки открытия файла }

   BITMAPFILEHEADER fhead,fhead_dest;
   BITMAPINFOHEADER ihead,ihead_dest;       //{ информация о картинке }

  nsigned char* rastr=NULL;
   __int8* turned_rastr=NULL;
   //{ байт, прочитанный из файла }
   short int b=0;
   int nb=0;    //{ кол-во байт (кратное четырем) соответствующее строке }
   long i, j;
   
   bmp_src= fopen(f_src, "rb");
   bmp_dest= fopen(f_dest, "wb");
   
   //Чтение заголовков
   fread(&fhead.bfType, 2, 1, bmp_src);[/HTML]
   fread(&fhead.bfSize, 4, 1, bmp_src);
   fread(&fhead.bfReserved1, 2, 1, bmp_src);
   fread(&fhead.bfReserved2, 2, 1, bmp_src);
   fread(&fhead.bfOffBits, 4, 1, bmp_src);

   fread(&ihead, sizeof(ihead), 1, bmp_src);
   
   if (ihead.biBitCount != 24)
    return(-2);    //Если картинка не 24-битная
   
   fhead_dest=fhead;
   ihead_dest=ihead;
   
    int nWidth ;
    int nHeight ;
    nWidth = ihead_dest.biWidth;
    nHeight = ihead_dest.biHeight;
    nWidth = QWIDTHBYTES(nWidth,8);
    int bmpsize = nWidth*nHeight;
    unsigned char * lpbit = new unsigned char[bmpsize];

    float fProportion = (float)85/100.f;// здесь пока что в ручную управляю размерность
    int tempw=nWidth, temph=nHeight;
    unsigned char * temp = new unsigned char[bmpsize];
    fseek(bmp_src, fhead.bfOffBits, SEEK_SET); //смещаемся к растру
    fread(lpbit,sizeof(bmpsize), 1, bmp_src);
    memcpy(temp,lpbit,tempw*temph);
    delete [] lpbit;
    lpbit=NULL;
   
    nWidth = (int)((float)nWidth*fProportion+0.5);
    nWidth = QWIDTHBYTES(nWidth,8);
    nHeight = (int)((float)nHeight*fProportion+0.5);

    if ((ihead.biWidth*3)%4 !=0 )
    nb=4-(ihead.biWidth*3)%4;

    lpbit = new unsigned char[nWidth*nHeight];
    // в цикле происходить сам процесс преобразования матрицы (в данном случае уменьшения на заданную fProportion)
    for (int i=0;i<nHeight;i++)
        for(int j=0;j<nWidth;j++)
        {
            int h,w;
            w = (int)((float)j/fProportion+0.5);
            h = (int)((float)i/fProportion+0.5);

            DWORD k = i*nWidth+j;
            DWORD l = h*tempw+w;
            if(h>=temph || w>=tempw)
                *(lpbit+k)=0;
            else
                *(lpbit+k)=*(temp+l);
        }
    delete [] temp;
    ihead_dest.biHeight=nHeight;
    ihead_dest.biWidth=nWidth;
    ihead_dest.biSizeImage=ihead_dest.biHeight*ihead_dest.biWidth*3+(4-(ihead_dest.biWidth*3)%4)*ihead_dest.biHeight;
    fhead_dest.bfSize = (ihead_dest.biHeight*ihead_dest.biWidth*3+fhead.bfOffBits+(4-(ihead_dest.biWidth*3)%4)*ihead_dest.biHeight);
   
    //Формирование заголовка выходного файла
    fwrite(&fhead_dest.bfType, 2, 1, bmp_dest);
   fwrite(&fhead_dest.bfSize, 4, 1, bmp_dest);
   fwrite(&fhead_dest.bfReserved1, 2, 1, bmp_dest);
   fwrite(&fhead_dest.bfReserved2, 2, 1, bmp_dest);
   fwrite(&fhead_dest.bfOffBits, 4, 1, bmp_dest);

   fwrite(&ihead_dest, sizeof(ihead), 1, bmp_dest);
   
   rastr=(unsigned char*)malloc(ihead.biSizeImage);
   
   fseek(bmp_src, fhead.bfOffBits, SEEK_SET); //смещаемся к растру
   fseek(bmp_dest, fhead_dest.bfOffBits, SEEK_SET); //смещаемся к растру
   //Чтение растра
   fread(rastr,ihead.biSizeImage,1,bmp_src);
   
   //Преобразование растра
   
   //Запись растра
   fwrite(rastr,ihead_dest.biSizeImage,1,bmp_dest);
   
   free(rastr);
 
   fclose(bmp_src);
   fclose(bmp_dest);

   return (-4);
}


На выходе изображения искажается, я пока не знаю как это исправить....и прошу помочь в этом. Спасибо.
57K
08 января 2011 года
sqwerty
34 / / 04.01.2011
входная изображения
и выходная изображения
57K
08 января 2011 года
sqwerty
34 / / 04.01.2011
Цитата: Yos
Предварительно ознакомившись с теорией - Роджерс Д. Алгоритмические основы машинной графики, 1989 год. Особенно то что касается спрайтовой анимации и найдите хорошую книгу по форматам графических файлов.



Я уже прочел эту книгу

5
08 января 2011 года
hardcase
4.5K / / 09.08.2005
Цитата: sqwerty
Я уже прочел эту книгу


Что мешает прочитать BMP в память (двумерный массив) любой доступной библиотекой, обработать как надо и обратно в BMP сохранить?

57K
08 января 2011 года
sqwerty
34 / / 04.01.2011
А что не так у меня в коде, что не могу получить на выходе нормальное изображения?
5
08 января 2011 года
hardcase
4.5K / / 09.08.2005
Цитата: sqwerty
А что не так у меня в коде, что не могу получить на выходе нормальное изображения?


Твою никак не отформатированную портянку ни один нормальный человек смотреть не будет.

342
08 января 2011 года
Yos
209 / / 21.06.2003
Цитата: sqwerty
А что не так у меня в коде, что не могу получить на выходе нормальное изображения?



давайте так - что значит обрезать по контуру и для чего это вам нужно. Как только объясните, я вам напишу "чистый" код чсла так 11... в качестве учебного пособия...

PS Я прочел кодец. там проще потратить пару часов на написание нового чем пару дней объяснять что к чему...

57K
08 января 2011 года
sqwerty
34 / / 04.01.2011
Цитата: Yos
давайте так - что значит обрезать по контуру и для чего это вам нужно. Как только объясните, я вам напишу "чистый" код числа так 11... в качестве учебного пособия...

PS Я прочел кодец. там проще потратить пару часов на написание нового чем пару дней объяснять что к чему...



Хорошо.
В общем, мне надо взять изображению YV12. Изменить размер (увеличить/уменьшить), обрезать, сместить и добавить шум. А потом попробовать восстановить исходную изображению.

И чтобы разница между исходной и выходной была минимальная. Это один из способов для выполнения одной задачи.

342
10 января 2011 года
Yos
209 / / 21.06.2003
Цитата: sqwerty
В общем, мне надо взять изображению YV12

изображение в этом формате прикрепите к сообщению, так как оно имеет отличную от ВМР растра (http://en.wikipedia.org/wiki/YV12#Y.27UV420p_.28and_Y.27V12.29) структуру - Сначала w*h картинка яркости, потом w/2 * h/2 картинка U, потом w/2 * h/2 картинка V. + надо делать преобразование в RGB...

PS я так и не увидел описания цели (что надо делать после понятно), но для чего - нет...

57K
12 января 2011 года
sqwerty
34 / / 04.01.2011
Изображению YV12 я получаю с помощью программы VirtualDub-1.9.11.

Цель, пока точно не ясно. Ну как, ясно, но боюсь рассказать, вдруг если не получиться задуманное, то это будет не к чему... А Вам зачем знать цель?

У меня пока сделано обрезания, resize (почти)....
342
13 января 2011 года
Yos
209 / / 21.06.2003
Так как вы предоставили изображение не в формате YV12 и к тому же к ВМР оно не имеет никакого отношения, а преобразования (в своем приведенном коде) делаете с ВМР 24, то я потратил сегодня те самые 2 часа (между всякими там совещениями по началу года) и написал все о чем говорил...

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

Особое внимание обратите на переменные в параметрах преобразований, так как проверок на их корректноть нет, но если они корректны, то работает с любыми размерами. Именно по этому применил "несколько отличные" функции для работы с файлами и памятью, но вы можете их легко заменить на привычные вам...
Код:
//*************************************************************

typedef struct _HICOLOR
{
    union
    {
        // цельный цвет
        DWORD   Color;

        // составляющие
        struct
        {
            BYTE    B;
            BYTE    G;
            BYTE    R;
            BYTE    Alpha;

        } Layer;
    };

} HICOLOR, *PHICOLOR, *LPHICOLOR;

//*************************************************************
//*
//* Старт программы
//*
//*************************************************************
int main(int Count, char ** pArguments)
{
 //****
 HANDLE                 hFile;

 BITMAPFILEHEADER       FileHeader;
 BITMAPINFOHEADER       InfoHeader;

 LPBYTE                 pFileData;
 LPHICOLOR              pImageData;

 DWORD                  Size;
 DWORD                  LineSize;

 DWORD                  FileOffset;
 DWORD                  ImageOffset;

 DWORD                  x;
 DWORD                  y;

 // открываем файл
 hFile = CreateFile(*(pArguments+1),GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
 // читаем заголовок файла
 ReadFile(hFile,(LPVOID)&FileHeader,sizeof(BITMAPFILEHEADER),&Size,NULL);
 // читаем заголовок изображения
 ReadFile(hFile,(LPVOID)&InfoHeader,sizeof(BITMAPINFOHEADER),&Size,NULL);

 // если это изображение R8G8B8
 if( InfoHeader.biBitCount == 24 )
 {
    // выделяем память под данные файла изображения
    pFileData = (LPBYTE)GlobalAlloc(GPTR,InfoHeader.biSizeImage);

    // читаем данные файла изображения
    SetFilePointer(hFile,FileHeader.bfOffBits,NULL,FILE_BEGIN);
    ReadFile(hFile,(LPVOID)pFileData,InfoHeader.biSizeImage,&Size,NULL);

    // закрываем файл
    CloseHandle(hFile);

    // вычисляем размер линии по горизонтали, так как она должна быть выравнена на DWORD
    // это нужно для дальнейших преобразований
    LineSize = InfoHeader.biSizeImage / InfoHeader.biHeight;

    // выделяем память под рабочие данные изображения
    pImageData = (LPHICOLOR)GlobalAlloc(GPTR,InfoHeader.biWidth*InfoHeader.biHeight*sizeof(HICOLOR));

    // формируем рабочее изображение
    for( y=0; y<InfoHeader.biHeight; y++ )
    {
        for( x=0; x<InfoHeader.biWidth; x++ )
        {
            // расчитываем смещения
            FileOffset = y * LineSize + x * 3;
            ImageOffset = y * InfoHeader.biWidth + x;

            // формируем рабочие данные
            (pImageData+ImageOffset)->Layer.Alpha = 0xFF;
            (pImageData+ImageOffset)->Layer.B = *(pFileData+FileOffset);
            (pImageData+ImageOffset)->Layer.G = *(pFileData+FileOffset+1);
            (pImageData+ImageOffset)->Layer.R = *(pFileData+FileOffset+2);
        }
    }

    // освобождаем ранее выделенную память под данные файла изображения
    GlobalFree(pFileData);

    // Изменяем размер
    Resize(&pImageData,(LPDWORD)&InfoHeader.biWidth,(LPDWORD)&InfoHeader.biHeight,InfoHeader.biWidth/2,InfoHeader.biHeight/2);

    // Обрезаем
    Cut(&pImageData,(LPDWORD)&InfoHeader.biWidth,(LPDWORD)&InfoHeader.biHeight,InfoHeader.biWidth/4,InfoHeader.biHeight/4,InfoHeader.biWidth*3/4,InfoHeader.biHeight*3/4);

    // Добавляем шум
    AppendNoise(pImageData,InfoHeader.biWidth,InfoHeader.biHeight);

    // вычисляем размер линии по горизонтали, так как она должна быть выравнена на DWORD
    // это нужно для дальнейших преобразований
    for( LineSize=InfoHeader.biWidth*3; (LineSize & 0x00000003); LineSize++ );

    // заполняем описание нового изображения
    InfoHeader.biSizeImage = LineSize * InfoHeader.biHeight;
    FileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + InfoHeader.biSizeImage;

    // выделяем память под данные файла изображения
    pFileData = (LPBYTE)GlobalAlloc(GPTR,InfoHeader.biSizeImage);

    // формируем готовое изображение
    for( y=0; y<InfoHeader.biHeight; y++ )
    {
        for( x=0; x<InfoHeader.biWidth; x++ )
        {
            // расчитываем смещения
            FileOffset = y * LineSize + x * 3;
            ImageOffset = y * InfoHeader.biWidth + x;

            // формируем рабочие данные
            *(pFileData+FileOffset) = (pImageData+ImageOffset)->Layer.B;
            *(pFileData+FileOffset+1) = (pImageData+ImageOffset)->Layer.G;
            *(pFileData+FileOffset+2) = (pImageData+ImageOffset)->Layer.R;
        }
    }

    // освобождаем ранее выделенную память под рабочие данные изображения
    GlobalFree(pImageData);

    // создаем файл
    hFile = CreateFile(*(pArguments+2),GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,0,NULL);
    // записываем заголовок файла
    WriteFile(hFile,(LPVOID)&FileHeader,sizeof(BITMAPFILEHEADER),&Size,NULL);
    // записываем заголовок изображения
    WriteFile(hFile,(LPVOID)&InfoHeader,sizeof(BITMAPINFOHEADER),&Size,NULL);
    // записываем само изображение
    WriteFile(hFile,(LPVOID)pFileData,InfoHeader.biSizeImage,&Size,NULL);

    // закрываем файл
    CloseHandle(hFile);

    // освобождаем ранее выделенную память под данные файла изображения
    GlobalFree(pFileData);
 }

 // закрываем файл
 else CloseHandle(hFile);

 return 0;
}
342
13 января 2011 года
Yos
209 / / 21.06.2003
А вот и сами функции преобразований:
Код:
//*************************************************************
//*
//* Обрезать
//*
//*************************************************************
void Cut(LPHICOLOR * pImageData, LPDWORD pWidth, LPDWORD pHeight, DWORD left, DWORD top, DWORD right, DWORD bottom)
{
 //****
 LPHICOLOR              pNewImageData;

 DWORD                  ImageOffset;
 DWORD                  NewImageOffset;

 DWORD                  x;
 DWORD                  y;

 DWORD                  width;
 DWORD                  height;

 // расчитываем новый размер
 width = right - left + 1;
 height = bottom - top + 1;

 // выделяем память под результирующие рабочие данные изображения
 pNewImageData = (LPHICOLOR)GlobalAlloc(GPTR,width*height*sizeof(HICOLOR));

 // формируем обрезанное рабочее изображение
 for( y=0; y<height; y++ )
 {
    for( x=0; x<width; x++ )
    {
        // расчитываем смещения
        ImageOffset = (y + top) * (*(pWidth)) + x + left;
        NewImageOffset = y * width + x;

        // формируем рабочие данные
        (pNewImageData+NewImageOffset)->Color = (*(pImageData)+ImageOffset)->Color;
    }
 }

 // освобождаем ранее выделенную память под рабочие данные изображения
 GlobalFree(*(pImageData));
 // и передаем новую
 *(pImageData) = pNewImageData;

 // возвращаем новые размеры
 *(pWidth) = width;
 *(pHeight) = height;
}

//*************************************************************
//*
//* Изменить размер
//*
//*************************************************************
void Resize(LPHICOLOR * pImageData, LPDWORD pWidth, LPDWORD pHeight, DWORD NewWidth, DWORD NewHeight)
{
 //****
 LPHICOLOR              pNewImageData;

 DWORD                  ImageOffset;
 DWORD                  NewImageOffset;

 DWORD                  X;
 DWORD                  Y;

 DWORD                  NewX;
 DWORD                  NewY;

 DWORD                  CountX;
 DWORD                  CountY;

 // выделяем память под результирующие рабочие данные изображения
 pNewImageData = (LPHICOLOR)GlobalAlloc(GPTR,NewWidth*NewHeight*sizeof(HICOLOR));

 // формируем рабочее изображение с новыми размерами
 // Основа этих "хитрых" преобразований корнями уходит в целочисленные методы формирования
 // графических примитивов по Брезенхему, с которыми вы должны быть знакомы, так как прочитали указанную мною книгу...
 for( Y=NewY=0,CountY=0; NewY<NewHeight; NewY++,CountY+=*(pHeight) )
 {
    while( CountY >= NewHeight )
    {
        CountY -= NewHeight;
        Y++;
    }

    for( X=NewX=0,CountX=0; NewX<NewWidth; NewX++,CountX+=*(pWidth) )
    {
        while( CountX >= NewWidth )
        {
            CountX -= NewWidth;
            X++;
        }

        // расчитываем смещения
        ImageOffset = Y * (*(pWidth)) + X;
        NewImageOffset = NewY * NewWidth + NewX;

        // формируем рабочие данные
        (pNewImageData+NewImageOffset)->Color = (*(pImageData)+ImageOffset)->Color;
    }
 }

 // освобождаем ранее выделенную память под рабочие данные изображения
 GlobalFree(*(pImageData));
 // и передаем новую
 *(pImageData) = pNewImageData;

 // возвращаем новые размеры
 *(pWidth) = NewWidth;
 *(pHeight) = NewHeight;
}

//*************************************************************
//*
//* Добавить шум
//*
//*************************************************************
void AppendNoise(LPHICOLOR pImageData, DWORD width, DWORD height)
{
 //****
 DWORD                  ImageOffset;

 DWORD                  x;
 DWORD                  y;

 SYSTEMTIME             time;

 DWORD                  Count;
 DWORD                  Random;

 BYTE                   gray;

 // инициализируем датчик случайных чисел на основании текущего времени
 GetLocalTime(&time);
 Random = time.wMilliseconds * time.wSecond * time.wMinute * time.wHour;

 // формиуруем шум
 for( Count=0; Count<10000; Count++ )
 {
    // генерируем положение
    Random = Random * 214013 + 2531011;
    x = Random % width;
    Random = Random * 214013 + 2531011;
    y = Random % height;

    // генерируем "цвет" шума - реализация может быть разной
    gray = (BYTE)(Random % 255);

    // расчитываем смещение
    ImageOffset = y * width + x;

    // формируем рабочие данные
    (pImageData+ImageOffset)->Layer.B = (pImageData+ImageOffset)->Layer.B * gray / 255;
    (pImageData+ImageOffset)->Layer.G = (pImageData+ImageOffset)->Layer.G * gray / 255;
    (pImageData+ImageOffset)->Layer.R = (pImageData+ImageOffset)->Layer.R * gray / 255;
 }
}
57K
13 января 2011 года
sqwerty
34 / / 04.01.2011
Yos, я вам очень благодарен за предоставленный код. Вы мне очень помогли в плане начинающего специалиста в этой области. А то у меня все время путаницы в коде. Особенно при записе в новый файл. Буду совершенствовать код, если удастся осуществить задуманный план.

Могу еще задавать вопросы или обратиться снова, если вдруг возникнут трудности?
Еще раз спасибо...
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог