ページ 11

バイナリデータを画像に変換

Posted: 2014年8月03日(日) 14:02
by 黒い影
現在ppmという拡張子のファイル(画像)をbmpまたはjpegに変換するプログラムを作成しています。
開発環境は、Borland C++ compilerを用いて、Cpadでコードを書いています。

ppmファイルから画像のサイズ等は取得でき、
画像部分のデータも文字の3次元配列として取得できたのですが、
それから画像を生成する方法がわかりません。

c#で書いたときはsetPxcelでできましたが、
c++での方法がわかりません。

使用するAPI等を教えていただけるとありがたいです。

以下現在のコードです。

コード:

#include <iostream>
#include <cstdio>
#include <fstream>
#include <string>
#include <cstdio>

#define sscanf_s sscanf
#define buffer line

using namespace std;

int main(void) 
{
    int x, y, color;
 
    std::ifstream file;
    
	// 画像格納配列
    static unsigned char image[1050][1050][3];
	
    // 読み込んだ画像の解像度
    int width = 0;
    int height = 0;
	
    // 読み込んだ画像の諧調数
    int max_gray = 0;
 
    // 画像のpath
    const char* name = "test.ppm";
 
   file.open(name,file.in | file.binary);
 
    // 画像の形式の取得
    std::string line;
    getline(file, line);
 
    // 画像の解像度の取得
    while ( width == 0 || height == 0 )
	{
        std::string line;
        std::getline(file, line);
		
        //コメント行を飛ばす
        if ( line.at(0) != '#' ) 
		{
            sscanf_s( line.c_str(), "%d %d", &width, &height );
        }
    }
 
    // 画像の諧調数の取得
    while (max_gray == 0)
	{
        std::string line;
        std::getline(file, line);
        if ( buffer[0] != '#' )
		{
            sscanf_s( line.c_str(), "%d", &max_gray );
        }
    }
 
    // 画像データの取得
    for(y=0; y<height; y++)
	{
        for(x=0; x<width; x++)
		{
            for(color=0; color<3; color++)
			{
                file.read(reinterpret_cast<char*>(&image[x][y][color]), 1);
            }
        }
    }
 
    printf("line = %s\n",line.c_str());
    printf("width = %d, height = %d\n",width, height);
    printf("max_gray = %d\n", max_gray);
    puts("image data:");
    for(y=0;y<height;y++) 
	{
        for(x=0;x<width;x++) 
		{
            for(color=0;color<3;color++) 
			{
				if(x+1==width && color+1==3)
				{
					printf("%3d\n", image[x][y][color]);
				}
				else
				{
					printf("%3d ", image[x][y][color]);
				}
            }
        }
    }
    return 0;
}

Re: バイナリデータを画像に変換

Posted: 2014年8月03日(日) 15:13
by h2so5
C++に画像出力用のAPIは標準で存在しないので出力コードを自作するか外部ライブラリを使う必要があります。

Re: バイナリデータを画像に変換

Posted: 2014年8月03日(日) 15:26
by 黒い影
h2so5 さんが書きました:C++に画像出力用のAPIは標準で存在しないので出力コードを自作するか外部ライブラリを使う必要があります。
h2so5さん、返信ありがとうございます。
openCVを用いればできるでしょうか?
openCVは今まで使ったことがないので、もしopenCVで可能ならば、
そちらについて少しでもご教授いただけるとありがたいです。

Re: バイナリデータを画像に変換

Posted: 2014年8月03日(日) 15:55
by h2so5
OpenCVでも可能です。

Re: バイナリデータを画像に変換

Posted: 2014年8月03日(日) 16:29
by softya(ソフト屋)
Libjpegや、WindowsならGDI+とか、bmpなら全部自分でバイナリ出力しても良いですし手はいくらでもあります。
課題なら何らかの制限があるはずですけどね。

Re: バイナリデータを画像に変換

Posted: 2014年8月03日(日) 16:54
by 黒い影
h2so5さん、ソフト屋さんありがとうございます。
これは、課題ではなく、部内の活動で使うのですが、周りにC/C++使いがあまりいなくて...

とりあえず、bmpで頑張ってみます!

Re: バイナリデータを画像に変換

Posted: 2014年8月03日(日) 19:36
by 黒い影
掲示板の過去ログをもとにして作ることができました。
以下コードです。
(ごちゃごちゃして、読みにくくすみません)

コード:

#include <iostream>
#include <cstdio>
#include <fstream>
#include <string>
#include <cstdio>
#include <windows.h>

#define sscanf_s sscanf
#define buffer line

using namespace std;

struct imageFile
{
	int width, height;
};
 
struct RGB
{
    BYTE red, green, blue;
};

imageFile ppmRead(const char *FileName);
void  bmpCreate(const char *FileName, imageFile ppm);

void InitBitmapFileHeader(BITMAPFILEHEADER *fileHeader, int width, int height);
void InitBitmapInfoHeader(BITMAPINFOHEADER *infoHeader, int width, int height);
void InitBitmapHeader(BITMAPFILEHEADER *fileHeader, BITMAPINFOHEADER *infoHeader, int width, int height);
void WriteBitmapHeader(FILE *fp, BITMAPFILEHEADER fileHeader, BITMAPINFOHEADER infoHeader);
void WriteBitmapLine(FILE *fp, imageFile ppm);

//画像データ
RGB images[1050][1050];
int main(void) 
{
	imageFile ppm;
	
	//ppm読み込み
	ppm = ppmRead("test.ppm");
	
	bmpCreate("test.bmp", ppm);
	
    return 0;
}

imageFile ppmRead(const char *FileName)
{
	int x, y, color;
 
    ifstream file;
	
    // 読み込んだ画像の解像度
    int width = 0;
    int height = 0;
	
	imageFile ppm;
	
    // 読み込んだ画像の諧調数
    int max_gray = 0;
 
    file.open(FileName ,file.in | file.binary);
 
    // 画像の形式の取得
    string line;
    getline(file, line);
 
    // 画像の解像度の取得
    while ( width == 0 || height == 0 )
	{
        string line;
        getline(file, line);
		
        //コメント行を飛ばす
        if ( line.at(0) != '#' ) 
		{
            sscanf_s( line.c_str(), "%d %d", &width, &height );
        }
    }
	
	ppm.width = width;
	ppm.height = height;
 
    // 画像の諧調数の取得
    while (max_gray == 0)
	{
        std::string line;
        std::getline(file, line);
        if ( buffer[0] != '#' )
		{
            sscanf_s( line.c_str(), "%d", &max_gray );
        }
    }
 
    // 画像データの取得
    for(y=0; y<height; y++)
	{
        for(x=0; x<width; x++)
		{
			file.read(reinterpret_cast<char*>(&images[x][y].red),   1);
        	file.read(reinterpret_cast<char*>(&images[x][y].green), 1);
			file.read(reinterpret_cast<char*>(&images[x][y].blue),  1);
		}
    }
/*
	printf("line = %s\n",line.c_str());
    printf("width = %d, height = %d\n",width, height);
    printf("max_gray = %d\n", max_gray);
    puts("image data (press key):");
	getchar();
    for(y=0;y<height;y++) 
	{
        for(x=0;x<width;x++) 
		{
			if(x+1==width)
			{
				printf("%3d %3d %3d\n", images[x][y].red, images[x][y].green, images[x][y].red);
			}
			else
			{
				printf("%3d %3d %3d ", images[x][y].red, images[x][y].green, images[x][y].red);
			}
        }
    }
	*/
	return ppm;
}

//BMPファイルに書き出す
void  bmpCreate(const char *FileName, imageFile ppm)
{
	BITMAPFILEHEADER fileHeader;
    BITMAPINFOHEADER infoHeader;
	
    FILE *fp = fopen(FileName, "wb");
 	imageFile FileData = ppm;
 	
    InitBitmapHeader(&fileHeader, &infoHeader, FileData.width, FileData.height); // ヘッダを作成
	
    WriteBitmapHeader(fp, fileHeader, infoHeader); // ヘッダを出力
 	
	WriteBitmapLine(fp, FileData);
	
    fclose(fp);
}

//BITMAPFILEHEADERを引数に従って初期化
void InitBitmapFileHeader(BITMAPFILEHEADER *fileHeader, int width, int height)
{
    int headerSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // BITMAPINFOHEADERと共に使用されることを前提
 
    fileHeader->bfType      = 'B' + 'M' * 0x100;
    fileHeader->bfSize      = width * height * 3 + headerSize;
    fileHeader->bfReserved1 = fileHeader->bfReserved2 = 0;
    fileHeader->bfOffBits   = headerSize;
}
 
//BITMAPINFOHEADERを引数に従って初期化
void InitBitmapInfoHeader(BITMAPINFOHEADER *infoHeader, int width, int height)
{
    memset(infoHeader, 0, sizeof(BITMAPINFOHEADER));
    infoHeader->biSize              = 40;
    infoHeader->biWidth             = width;
    infoHeader->biHeight            = height;
    infoHeader->biPlanes            = 1;
    infoHeader->biBitCount          = 32; // true color(4byte)
}
 
//BITMAPFILEHEADERとBITMAPINFOHEADERを引数に従って初期化
void InitBitmapHeader(BITMAPFILEHEADER *fileHeader, BITMAPINFOHEADER *infoHeader, int width, int height)
{
    InitBitmapFileHeader(fileHeader, width, height);
    InitBitmapInfoHeader(infoHeader, width, height);
}
 
//ビットマップヘッダをファイルに書き出す
void WriteBitmapHeader(FILE *fp, BITMAPFILEHEADER fileHeader, BITMAPINFOHEADER infoHeader)
{
    fwrite(&fileHeader, sizeof(BITMAPFILEHEADER), 1, fp);
    fwrite(&infoHeader, sizeof(BITMAPINFOHEADER), 1, fp);
}

//RGBデータをファイルに出力
void WriteBitmapLine(FILE *fp, imageFile ppm)
{
    BYTE padding = 0;
 
    for (int y = 0; y < ppm.height; y++)
    {
		for (int x = 0; x < ppm.width; x++)
		{
        	fwrite(&images[x][y].blue,  sizeof(BYTE), 1, fp);
        	fwrite(&images[x][y].green, sizeof(BYTE), 1, fp);
        	fwrite(&images[x][y].red,   sizeof(BYTE), 1, fp);
        	fwrite(&padding,      sizeof(BYTE), 1, fp);
		}
	}
}

Re: バイナリデータを画像に変換

Posted: 2014年8月03日(日) 19:37
by 黒い影
解決忘れてました