7

2Dマトリックスを含むマトリックスライブラリによって保存されているテキストファイルがあります。

1 0 0 
6 0 4
0 1 1

各番号は色付きのピクセルで表されます。この問題をどのように解決するかについての洞察を探しています。さらに情報が必要な場合は、遠慮なくお問い合わせください。

編集:私が試したもう1つのアプローチはfwrite(&intmatrix, size,1, bmp_ptr);、読み取り可能なBMPファイルを出力していないように見えるマトリックスポインターを渡すことです。の値はsizeもちろんrows*colsです。行列のタイプはarma::Mat<int>、Armadillo線形代数ライブラリの行列です。

編集II:これを読んだことは、私が間違っていなければ、私のサイズはおそらく行のサイズを考えると行*列* 4であるべきであることを示しました、この点に関するガイダンスも素晴らしいでしょう。

4

5 に答える 5

13

これは、ランダムな整数のテキスト ファイルを生成し、それらを読み取り、(ほぼ正方形の) 32 ビット/ピクセルの .BMP イメージとしてディスクに書き込むアプリです。

元のテキスト ファイルの形式、数値の範囲などについていくつかの仮定を立てましたが、それらはコードに記載されていることに注意してください。この実際の例では、必要に応じて簡単に微調整できるはずです。

// IntToBMP.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <cstdint>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <random>
#include <ctime>
#include <memory>

#pragma pack( push, 1 ) 
struct BMP
{
    BMP();
    struct
    {
        uint16_t ID;
        uint32_t fileSizeInBytes;
        uint16_t reserved1;
        uint16_t reserved2;
        uint32_t pixelArrayOffsetInBytes;
    } FileHeader;

    enum class CompressionMethod : uint32_t {   BI_RGB              = 0x00, 
                                                BI_RLE8             = 0x01,
                                                BI_RLE4             = 0x02,
                                                BI_BITFIELDS        = 0x03,
                                                BI_JPEG             = 0x04,
                                                BI_PNG              = 0x05,
                                                BI_ALPHABITFIELDS   = 0x06 };

    struct
    {
        uint32_t headerSizeInBytes;
        uint32_t bitmapWidthInPixels;
        uint32_t bitmapHeightInPixels;
        uint16_t colorPlaneCount;
        uint16_t bitsPerPixel;
        CompressionMethod compressionMethod;
        uint32_t bitmapSizeInBytes;
        int32_t horizontalResolutionInPixelsPerMeter;
        int32_t verticalResolutionInPixelsPerMeter;
        uint32_t paletteColorCount;
        uint32_t importantColorCount;
    } DIBHeader;
};
#pragma pack( pop )

BMP::BMP()
{
    //Initialized fields
    FileHeader.ID                                   = 0x4d42; // == 'BM' (little-endian)
    FileHeader.reserved1                            = 0;
    FileHeader.reserved2                            = 0;
    FileHeader.pixelArrayOffsetInBytes              = sizeof( FileHeader ) + sizeof( DIBHeader );
    DIBHeader.headerSizeInBytes                     = 40;
    DIBHeader.colorPlaneCount                       = 1;
    DIBHeader.bitsPerPixel                          = 32;
    DIBHeader.compressionMethod                     = CompressionMethod::BI_RGB;
    DIBHeader.horizontalResolutionInPixelsPerMeter  = 2835; // == 72 ppi
    DIBHeader.verticalResolutionInPixelsPerMeter    = 2835; // == 72 ppi
    DIBHeader.paletteColorCount                     = 0;
    DIBHeader.importantColorCount                   = 0;
}

void Exit( void )
{
    std::cout << "Press a key to exit...";
    std::getchar();

    exit( 0 );
}

void MakeIntegerFile( const std::string& integerFilename )
{
    const uint32_t intCount = 1 << 20; //Generate 1M (2^20) integers
    std::unique_ptr< int32_t[] > buffer( new int32_t[ intCount ] ); 

    std::mt19937 rng;
    uint32_t rngSeed = static_cast< uint32_t >( time( NULL ) );
    rng.seed( rngSeed );

    std::uniform_int_distribution< int32_t > dist( INT32_MIN, INT32_MAX );

    for( size_t i = 0; i < intCount; ++i )
    {
        buffer[ i ] = dist( rng );
    }

    std::ofstream writeFile( integerFilename, std::ofstream::binary );

    if( !writeFile )
    {
        std::cout << "Error writing " << integerFilename << ".\n";
        Exit();
    }

    writeFile << buffer[ 0 ];
    for( size_t i = 1; i < intCount; ++i )
    {
        writeFile << " " << buffer[ i ];
    }
}

int _tmain(int argc, _TCHAR* argv[])  //Replace with int main( int argc, char* argv[] ) if you're not under Visual Studio
{
    //Assumption: 32-bit signed integers
    //Assumption: Distribution of values range from INT32_MIN through INT32_MAX, inclusive
    //Assumption: number of integers contained in file are unknown
    //Assumption: source file of integers is a series of space-delimitied strings representing integers
    //Assumption: source file's contents are valid
    //Assumption: non-rectangular numbers of integers yield non-rectangular bitmaps (final scanline may be short)
    //            This may cause some .bmp parsers to fail; others may pad with 0's.  For simplicity, this implementation
    //            attempts to render square bitmaps.

    const std::string integerFilename = "integers.txt";
    const std::string bitmapFilename = "bitmap.bmp";

    std::cout << "Creating file of random integers...\n";
    MakeIntegerFile( integerFilename );

    std::vector< int32_t >integers; //If quantity of integers being read is known, reserve or resize vector or use array

    //Read integers from file
    std::cout << "Reading integers from file...\n";
    {   //Nested scope will release ifstream resource when no longer needed
        std::ifstream readFile( integerFilename );

        if( !readFile )
        {
            std::cout << "Error reading " << integerFilename << ".\n";
            Exit();
        }

        std::string number;
        while( readFile.good() )
        {
            std::getline( readFile, number, ' ' );
            integers.push_back( std::stoi( number ) );
        }

        if( integers.size() == 0 )
        {
            std::cout << "No integers read from " << integerFilename << ".\n";
            Exit();
        }
    }

    //Construct .bmp
    std::cout << "Constructing .BMP...\n";
    BMP bmp;
    size_t intCount = integers.size();
    bmp.DIBHeader.bitmapSizeInBytes = intCount * sizeof( integers[ 0 ] );
    bmp.FileHeader.fileSizeInBytes = bmp.FileHeader.pixelArrayOffsetInBytes + bmp.DIBHeader.bitmapSizeInBytes;
    bmp.DIBHeader.bitmapWidthInPixels = static_cast< uint32_t >( ceil( sqrt( intCount ) ) );
    bmp.DIBHeader.bitmapHeightInPixels = static_cast< uint32_t >( ceil( intCount / static_cast< float >( bmp.DIBHeader.bitmapWidthInPixels ) ) );

    //Write integers to .bmp file
    std::cout << "Writing .BMP...\n";
    {
        std::ofstream writeFile( bitmapFilename, std::ofstream::binary );

        if( !writeFile )
        {
            std::cout << "Error writing " << bitmapFilename << ".\n";
            Exit();
        }

        writeFile.write( reinterpret_cast< char * >( &bmp ), sizeof( bmp ) );
        writeFile.write( reinterpret_cast< char * >( &integers[ 0 ] ), bmp.DIBHeader.bitmapSizeInBytes );
    }

    //Exit
    Exit();
} 

お役に立てれば。

于 2012-09-03T05:58:17.850 に答える
6

適切な画像形式を選択すれば、これは非常に簡単です。 PGMには、マトリックスとほぼ同じように見える ASCII バリアントがありますが、ヘッダーがあります。

P2
3 3
6
1 0 0 
6 0 4
0 1 1

P2ASCII PGM のマジックはどこにあり、サイズは 3x3 で 6 はmaxval. 私が 6 を選択したのは、それがあなたが提示した最大値であり、6 が白 (0 が黒) になるためです。典型的な PGM では 255 で、これは 8 ビットのグレースケール イメージと一致しています。

PPMはほぼ単純で、ピクセルごとに 1 つではなく 3 つの色成分しかありません。

これらのイメージは、PPM (netpbm、ImageMagick、GIMP など) を使用するものなら何でも操作できます。基本的に同等の BMP と同じサイズのバイナリ PPM として再保存できます。

于 2012-09-05T01:01:27.633 に答える
5

読み取り可能な BMP ファイルを出力するには、最初にヘッダーを配置する必要があります。

#include <WinGDI.h>

DWORD dwSizeInBytes = rows*cols*4; // when your matrix contains RGBX data)

// fill in the headers
BITMAPFILEHEADER bmfh;
bmfh.bfType = 0x4D42; // 'BM'
bmfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwSizeInBytes;
bmfh.bfReserved1 = 0;
bmfh.bfReserved2 = 0;
bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

BITMAPINFOHEADER bmih;
bmih.biSize = sizeof(BITMAPINFOHEADER);
bmih.biWidth = cols;
bmih.biHeight = rows;
bmih.biPlanes = 1;
bmih.biBitCount = 32;
bmih.biCompression = BI_RGB;
bmih.biSizeImage = 0;
bmih.biXPelsPerMeter = 0;
bmih.biYPelsPerMeter = 0;
bmih.biClrUsed = 0;
bmih.biClrImportant = 0;

色情報を書き込む前に、ビットマップ ヘッダーを書き込むだけです。

fwrite(&bmfh, sizeof(bmfh),1, bmp_ptr);
fwrite(&bmih, sizeof(bmih),1, bmp_ptr);

そして最後に色情報:

fwrite(&intmatrix, size, sizeof(int), bmp_ptr);

マトリックスには単一の文字は含まれていませんが、各値の整数が含まれているため、ブロックサイズは sizeof(int) であることに注意してください。マトリックスの内容によっては、値を COLORREF 値に変換することをお勧めします (WinGDI.h にもある RGB マクロを確認してください)。

于 2012-09-01T15:38:29.377 に答える
1

https://stackoverflow.com/a/2654860/586784からの回答を書き直してコメントしました。十分に理解していただければ幸いです。

#include <cstddef>
#include <armadillo>
#include <map>
#include <cstdio>
#include <cassert>

///Just a tiny struct to bundle three values in range [0-255].
struct Color{
  Color(unsigned char red, unsigned char green, unsigned char blue)
    : red(red),green(green),blue(blue)
  {}

  ///Defualt constructed Color() is black.
  Color()
    : red(0),green(0),blue(0)
  {}

  ///Each color is represented by a combination of red, green, and blue.
  unsigned char red,green,blue;
};


int main(int argc,char**argv)
{

  ///The width of the image. Replace with your own.
  std::size_t w = 7;
  ///The height of the image. Replace with your own
  std::size_t h = 8;

  ///http://arma.sourceforge.net/docs.html#Mat
  ///The Armadillo Linear Algebra Library Mat constructor is of the following
  /// signature: mat(n_rows, n_cols).
  arma::Mat<int> intmatrix(h,w);

  ///Fill out matrix, replace this with your own.
  {

    ///Zero fill matrix
    for(std::size_t i=0; i<h; ++i)
      for(std::size_t j=0;j<w; ++j)
        intmatrix(i,j) = 0;

    intmatrix(0,3) = 1;
    intmatrix(1,3) = 1;


    intmatrix(2,2) = 6;
    intmatrix(2,4) = 6;

    intmatrix(3,2) = 4;
    intmatrix(3,4) = 4;


    intmatrix(4,1) = 6;
    intmatrix(4,2) = 6;
    intmatrix(4,3) = 6;
    intmatrix(4,4) = 6;
    intmatrix(4,5) = 6;

    intmatrix(5,1) = 1;
    intmatrix(5,2) = 1;
    intmatrix(5,3) = 1;
    intmatrix(5,4) = 1;
    intmatrix(5,5) = 1;


    intmatrix(6,0) = 4;
    intmatrix(6,6) = 4;

    intmatrix(7,0) = 6;
    intmatrix(7,6) = 6;

  }


  ///Integer to color associations. This is a map
  ///that records the meanings of the integers in the matrix.
  ///It associates a color with each integer.
  std::map<int,Color> int2color;

  ///Fill out the color associations. Replace this with your own associations.
  {
    ///When we see 0 in the matrix, we will use this color (red-ish).
    int2color[0] = Color(255,0,0);
    ///When we see 0 in the matrix, we will use this color (green-ish).
    int2color[1] = Color(0,255,0);
    ///When we see 0 in the matrix, we will use this color (blue-ish).
    int2color[4] = Color(0,0,255);
    ///When we see 0 in the matrix, we will use this color (grey-ish).
    int2color[6] = Color(60,60,60);
  }


  ///The file size will consist of w*h pixels, each pixel will have an RGB,
  /// where each color R,G,B is 1 byte, making the data part of the file to
  /// be of size 3*w*h. In addition there is a header to the file which will
  /// take of 54 bytes as we will see.
  std::size_t filesize = 54 + 3*w*h;


  ///We make an array of 14 bytes to represent one part of the header.
  ///It is filled out with some default values, and we will fill in the
  ///rest momentarily.
  unsigned char bmpfileheader[14] = {'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0};

  ///The second part of the header is 40 bytes; again we fill it with some
  ///default values, and will fill in the rest soon.
  unsigned char bmpinfoheader[40] = {40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0};



  ///We will now store the filesize,w,h into the header.
  ///We can't just write them to the file directly, because different platforms
  ///encode their integers in different ways. This is called "endianness"
  ///or "byte order". So we chop our integers up into bytes, and put them into
  ///the header byte-by-byte in the way we need to.


  ///Encode the least significant 8 bits of filesize into this byte.
  ///Because sizeof(unsigned char) is one byte, and one byte is eight bits,
  ///when filesize is casted to (unsigned char) only the least significant
  ///8 bits are kept and stored into the byte.
  bmpfileheader[ 2] = (unsigned char)(filesize    );
  ///... Now we shift filesize to the right 1 byte, meaning and trunctate
  ///that to its least significant 8 bits. This gets stored in the next
  ///byte.
  bmpfileheader[ 3] = (unsigned char)(filesize>> 8);
  ///...
  bmpfileheader[ 4] = (unsigned char)(filesize>>16);
  ///Encodes the most significant 8 bits of filesize into this byte.
  bmpfileheader[ 5] = (unsigned char)(filesize>>24);

  ///Now we will store w (the width of the image) in the same way,
  /// but into the byte [5-8] in bmpinfoheader.
  bmpinfoheader[ 4] = (unsigned char)(       w    );
  bmpinfoheader[ 5] = (unsigned char)(       w>> 8);
  bmpinfoheader[ 6] = (unsigned char)(       w>>16);
  bmpinfoheader[ 7] = (unsigned char)(       w>>24);



  ///Now we will store h (the width of the image) in the same way,
  /// but into the byte [9-12] in bmpinfoheader.
  bmpinfoheader[ 8] = (unsigned char)(       h    );
  bmpinfoheader[ 9] = (unsigned char)(       h>> 8);
  bmpinfoheader[10] = (unsigned char)(       h>>16);
  bmpinfoheader[11] = (unsigned char)(       h>>24);

  ///Now we open the output file
  FILE* f = fopen("img.bmp","wb");

  ///First write the bmpfileheader to the file. It is 14 bytes.
  ///The 1 means we are writing 14 elements of size 1.
  ///Remember, bmpfileheader is an array which is basically
  ///the same thing as saying it is a pointer to the first element
  ///in an array of contiguous elements. We can thus say:
  ///write 14 bytes, starting from the spot where bmpfileheader points
  ///to.
  fwrite(bmpfileheader,1,14,f);
  ///Then write the bmpinfoheader, which is 40 bytes, in the same way.
  fwrite(bmpinfoheader,1,40,f);

  ///Now we write the data.
  ///For each row (there are h rows), starting from the last, going
  ///up to the first.
  ///We iterate through the rows in reverse order here,
  ///apparently in the BMP format, the image
  ///is stored upside down.
  for(std::size_t i=h-1; i != std::size_t(-1); --i)
  {
    ///For each column in the row,
    for(std::size_t j=0; j<w; ++j)
    {

      ///We retreive the integer of the matrix at (i,j),
      ///and assert that there is a color defined for it.
      assert (int2color.count(intmatrix(i,j)) != 0
        && "Integer in matrix not defined in int2color map");

      ///We somehow get the color for pixel (i,j).
      ///In our case, we get it from the intmatrix, and looking
      ///up the integer's color.
      Color color = int2color[intmatrix(i,j)];

      ///Now the colors are written in reverse order: BGR

      ///We write the color using fwrite, by taking a pointer
      ///of the (unsigned char), which is the same thing as
      ///an array of length 1. Then we write the byte.
      ///First for blue,
      fwrite(&color.blue,1,1,f);
      ///Same for green,
      fwrite(&color.green,1,1,f);
      ///Finally red.
      fwrite(&color.red,1,1,f);
    }


    ///Now we do some padding, from 0-3 bytes, depending in the width.
    unsigned char bmppad[3] = {0,0,0};
    fwrite(bmppad,1,(4-(w*3)%4)%4,f);
  }

  ///Free the file.
  fclose(f);


  return 0;
}
于 2012-09-07T19:03:15.660 に答える
0

マトリックスを画像として見ること、またはコードから画像を書き込むことに問題がありますか?

前者の場合、ベン・ジャクソンが言ったように

後者の場合、Arm::Matrix のデータ ポインターのアドレスを渡す必要があり、fwrite を使用すると、Arm::Matrix がそのデータを連続したメモリ配列として保持していると想定されます。

[編集] armadillo doc を簡単に見てみると、データが列優先モードで保存されていることもわかりますが、BMP は行優先モードを想定しているため、画像が反転して見えます

[edit2] Armadillo Matrix 関数を使用すると、さらに簡単になります

// assume A is a matrix
// and maxVal is the maximum int value in you matrix (you might scale it to maxVal = 255)
std::ofstream outfile("name.pgm");
oufile << "P2 " << sd::endl << a.n_rows << " " << a.n_cols << std::endl << maxVal << std::endl;
outfile << a << std::endl;
outfile.close();
于 2012-09-07T14:55:08.020 に答える