質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.80%

visual Studio における画像ファイルの扱い方 C/C++

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 853

Kanaya979

score 13

前提・実現したいこと

C++でライブラリ(OpenCV)を使わずにトリミングをするシステムを作っています。
Visual Studio2017のソースファイルに下記のmain.cとkii.bmpを置いたのですが下記のようなエラーが出てしまいました
コンパイル画面?にはファイルが開けませんでした と出ます

発生している問題・エラーメッセージ

'ver5.14.exe' (Win32): 'C:\Users\shinohara yuki\source\repos\BMPcut\Debug\ver5.14.exe' が読み込まれました。シンボルが読み込まれました。
'ver5.14.exe' (Win32): 'C:\Windows\SysWOW64\ntdll.dll' が読み込まれました。PDB ファイルを開けないか、ファイルが見つかりません。
'ver5.14.exe' (Win32): 'C:\Windows\SysWOW64\kernel32.dll' が読み込まれました。PDB ファイルを開けないか、ファイルが見つかりません。
'ver5.14.exe' (Win32): 'C:\Windows\SysWOW64\KernelBase.dll' が読み込まれました。PDB ファイルを開けないか、ファイルが見つかりません。
'ver5.14.exe' (Win32): 'C:\Windows\SysWOW64\msvcp140d.dll' が読み込まれました。PDB ファイルを開けないか、ファイルが見つかりません。
'ver5.14.exe' (Win32): 'C:\Windows\SysWOW64\vcruntime140d.dll' が読み込まれました。PDB ファイルを開けないか、ファイルが見つかりません。
'ver5.14.exe' (Win32): 'C:\Windows\SysWOW64\ucrtbased.dll' が読み込まれました。PDB ファイルを開けないか、ファイルが見つかりません。
Debug Assertion Failed!

Program: C:\Users\shinohara yuki\source\repos\BMPcut\Debug\ver5.14.exe
File: minkernel\crts\ucrt\src\appcrt\stdio\fread.cpp
Line: 48

Expression: stream != nullptr

For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.

(Press Retry to debug the application)
スレッド 0x32e8 はコード 0 (0x0) で終了しました。

該当のソースコード

#pragma warning(disable:4996)

#include <cstdio>  
#include <iostream>  
#include <cstring>  

#define FILE_HEADER_SIZE 14                // ファイルヘッダのサイズ  
#define INFO_HEADER_SIZE 40                // 情報ヘッダのサイズ  

using namespace std;

/*
* ファイルヘッダー構造体
*/
typedef struct FileHeader {
    uint8_t data[FILE_HEADER_SIZE];  // 加工前データ(書き出しのため必要)  
    string fileType;                 // ファイルタイプ  
    int fileSize;                    // ファイルサイズ  
} FileHeader;

/*
* 情報ヘッダー構造体
*/
typedef struct InfoHeader {
    uint8_t data[INFO_HEADER_SIZE];  // 加工前データ(書き出しのため必要)  
    int infoHeaderSize;              // 情報ヘッダのサイズ  
    int width;                       // 画像の幅  
    int height;                      // 画像の高さ  
    int clrPerPixel;                 // 1ピクセル当たりの色数  
    int dataSize;                    // 画像データのサイズ  
} InfoHeader;

/*
* ピクセルの色情報構造体
*/
typedef struct Color {
    int r;                // 赤成分  
    int g;                // 緑成分  
    int b;                // 青成分  
} Color;

int bit2Integer(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4);

/*
* ビットマップ処理クラス
*/
class BitMapProcessor {
    FILE *bmp;               // ビットマップのファイルポインタ  
    uint8_t *img;            // ビットマップデータ(加工用)  
    uint8_t *org;            // ビットマップデータ(読み込み時)  
    FileHeader fHeader;      // ファイルヘッダ  
    InfoHeader iHeader;      // 情報ヘッダ  

public:
    BitMapProcessor() {
        bmp = NULL;
        img = NULL;
        org = NULL;
    };

    ~BitMapProcessor() {
        fclose(bmp);
        delete[]img;
        delete[]org;
    }
    void loadData(string filename);
    void dispBmpInfo();
    void writeData(string filename);
    Color getColor(int row, int col);
    void setColor(int row, int col, int r, int g, int b);
    void restore();
    int height() { return iHeader.height; };
    int width() { return iHeader.width; };
private:
    void readFileHeader();
    void readInfoHeader();
    void readBmpData();

};

/*
* 4ビット情報をInt整数値に変換
*/
int bit2Integer(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) {
    return b1 +
        b2 * 256 +
        b3 * 256 * 256 +
        b4 * 256 * 256 * 256;
}

/*
* ビットマップデータをロードする
*/
void BitMapProcessor::loadData(string filename) {
    if (bmp != NULL)
        fclose(bmp);

    bmp = fopen(filename.c_str(), "rb");
    if (bmp == NULL)
        printf("ファイルオープンに失敗しました。\n");

    readFileHeader();
    readInfoHeader();
    readBmpData();
}

/*
* ファイルヘッダを読む
*/
void BitMapProcessor::readFileHeader() {
    uint8_t data[FILE_HEADER_SIZE];
    size_t size = fread(data, sizeof(uint8_t), FILE_HEADER_SIZE, bmp);

    memcpy(fHeader.data, data, sizeof(data));
    fHeader.fileType = "";
    fHeader.fileType += data[0];
    fHeader.fileType += data[1];
    fHeader.fileSize = bit2Integer(data[2], data[3], data[4], data[5]);
}

/*
* 情報ヘッダを読む
*/
void BitMapProcessor::readInfoHeader() {
    uint8_t data[INFO_HEADER_SIZE];
    size_t size = fread(data, sizeof(uint8_t), INFO_HEADER_SIZE, bmp);

    memcpy(iHeader.data, data, sizeof(data));
    iHeader.infoHeaderSize = bit2Integer(data[0], data[1], data[2], data[3]);
    iHeader.width = bit2Integer(data[4], data[5], data[6], data[7]);
    iHeader.height = bit2Integer(data[8], data[9], data[10], data[11]);
    iHeader.clrPerPixel = bit2Integer(data[14], data[15], 0, 0);
    iHeader.dataSize = bit2Integer(data[20], data[21], data[22], data[23]);
}

/*
* 画像データを読む
*/
void BitMapProcessor::readBmpData() {
    if (img != NULL)
        delete[]img;

    int sz = iHeader.dataSize;
    img = new uint8_t[sz];
    size_t size = fread(img, sizeof(uint8_t), sz, bmp);
    if (size != sz)
        printf("画像データ読み込みのサイズが矛盾しています。");

    // バックアップ用にorgに画像データをコピー  
    if (org != NULL)
        delete[]org;
    org = new uint8_t[sz];
    memcpy(org, img, sz);
}

/*
* ビットマップ情報の表示(デバッグ用)
*/
void BitMapProcessor::dispBmpInfo() {
    cout << "■ファイルヘッダ情報" << endl;
    cout << "ファイルタイプ: " << fHeader.fileSize << endl;
    cout << "ファイルサイズ: " << fHeader.fileSize << endl;

    cout << "■情報ヘッダ情報" << endl;
    cout << "情報ヘッダサイズ: " << iHeader.infoHeaderSize << endl;
    cout << "画像幅: " << iHeader.width << endl;
    cout << "画像高: " << iHeader.height << endl;
    cout << "1ピクセルあたりの色数: " << iHeader.clrPerPixel << endl;
    cout << "画像データのサイズ: " << iHeader.dataSize << endl;
}

/*
* ビットマップデータのファイル書き出し
*/
void BitMapProcessor::writeData(string filename) {
    FILE *out = fopen(filename.c_str(), "wb");

    if (out == NULL)
        printf("書き出し先のファイルを開けません。\n");

    fwrite(fHeader.data, sizeof(uint8_t), FILE_HEADER_SIZE, out);
    fwrite(iHeader.data, sizeof(uint8_t), INFO_HEADER_SIZE, out);
    fwrite(img, sizeof(uint8_t), iHeader.dataSize, out);

    fclose(out);
}

/*
* 指定されたピクセルの色を取得
*/
Color BitMapProcessor::getColor(int row, int col) {
    if (row < 0 || row >= iHeader.height)
        printf("getColor(): rowが範囲外です。\n");
    if (col < 0 || col >= iHeader.width)
        printf("getColor(): colが範囲外です。\n");

    int width = 3 * iHeader.width;
    while (width % 4)        // ビットマップの1列は4の倍数ビットからなる  
        ++width;

    int bPos = row * width + 3 * col;
    int gPos = bPos + 1;
    int rPos = bPos + 2;

    Color color;
    color.r = img[rPos];
    color.g = img[gPos];
    color.b = img[bPos];

    return color;
}

/*
* 指定されたピクセルに色を設定
*/
void BitMapProcessor::setColor(int row, int col, int r, int g, int b) {
    if (row < 0 || row >= iHeader.height)
        printf("getColor(): rowが範囲外です。\n");
    if (col < 0 || col >= iHeader.width)
        printf("getColor(): colが範囲外です。\n");

    int width = 3 * iHeader.width;
    while (width % 4)        // ビットマップの1列は4の倍数ビットからなる  
        ++width;

    int bPos = row * width + 3 * col;
    int gPos = bPos + 1;
    int rPos = bPos + 2;

    img[rPos] = r;
    img[gPos] = g;
    img[bPos] = b;
}

/*
* ビットマップデータを加工前に復元する
*/
void BitMapProcessor::restore() {
    memcpy(img, org, iHeader.dataSize);
}


/*
* テスト用関数(1)モノクロ化
*/
void twoTone(BitMapProcessor *bmp) {
    for (int i = 0; i < bmp->height(); i++)
        for (int j = 0; j < bmp->width(); j++) {
            int ave = 0;
            ave += bmp->getColor(i, j).r;
            ave += bmp->getColor(i, j).g;
            ave += bmp->getColor(i, j).b;
            ave /= 3;

            bmp->setColor(i, j, ave, ave, ave);
        }
}

/*
* テスト関数(2)指定範囲の切り取り
*/
void extractArea(BitMapProcessor *bmp, int r0, int r1, int c0, int c1) {
    for (int i = 0; i < bmp->height(); i++)
        for (int j = 0; j < bmp->width(); j++) {
            if (r0 <= i && i <= r1 && c0 <= j && j <= c1)
                continue;
            bmp->setColor(i, j, 255, 255, 255);
        }
}

/*
* テスト関数(3) 色の反転
*/
void invert(BitMapProcessor *bmp) {
    for (int i = 0; i < bmp->height(); i++)
        for (int j = 0; j < bmp->width(); j++) {
            int ave = 0;
            int r = bmp->getColor(i, j).r;
            int g = bmp->getColor(i, j).g;
            int b = bmp->getColor(i, j).b;

            bmp->setColor(i, j, 255 - r, 255 - g, 255 - b);
        }
}

/*
* テスト関数(4)モザイク化
*/
void mosaic(BitMapProcessor *bmp, int level) {
    if (level <= 0)
        level = 1;

    for (int i = 0; i < bmp->height(); i += 2 * level)
        for (int j = 0; j < bmp->width(); j += 2 * level) {
            int r = 0;
            int g = 0;
            int b = 0;
            int cnt = 0;

            for (int x = -level; x <= level; x++)
                for (int y = -level; y <= level; y++) {
                    int xt = i + x;
                    int yt = j + y;

                    if (xt < 0 || yt < 0 || xt >= bmp->height() || yt >= bmp->width())
                        continue;
                    ++cnt;
                    r += bmp->getColor(xt, yt).r;
                    g += bmp->getColor(xt, yt).g;
                    b += bmp->getColor(xt, yt).b;
                }

            r /= cnt;
            g /= cnt;
            b /= cnt;

            for (int x = -level; x <= level; x++)
                for (int y = -level; y <= level; y++) {
                    int xt = i + x;
                    int yt = j + y;

                    if (xt < 0 || yt < 0 || xt >= bmp->height() || yt >= bmp->width())
                        continue;

                    bmp->setColor(xt, yt, r, g, b);
                }
        }
}

/*
* メイン処理
*/
int main() {
    BitMapProcessor bmp;

    // ビットマップデータのロード  
    bmp.loadData("filename");

    // ビットマップ情報の表示  
    bmp.dispBmpInfo();

    // テスト1. モノクロ化  
    twoTone(&bmp);
    bmp.writeData("kii_1.bmp");
    bmp.restore();

    // テスト2. 指定範囲の切り出し  
    extractArea(&bmp, 200, 300, 100, 180);
    bmp.writeData("kii_2.bmp");
    bmp.restore();

    // テスト3. 色反転  
    invert(&bmp);
    bmp.writeData("kii_3.bmp");
    bmp.restore();

    // テスト4. モザイク  
    mosaic(&bmp, 30);
    bmp.writeData("kii_4.bmp");
    bmp.restore();

    return 0;
}

試したこと

visualstudioのソースファイルにkii.bmpを貼り付け
"C:\Users\shinohara yuki\source\repos\BMPcut\ver5.14\kii.bmp" にkii.bmpを貼り付け

補足情報(FW/ツールのバージョンなど)

http://techtipshoge.blogspot.com/2011/07/blog-post_23.htmlより引用

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

+1

freadにてstream != nullptrのアサートが失敗しているとのことなので
ファイルのオープンに失敗している事が考えられます。

void BitMapProcessor::loadData(string filename) {
    if (bmp != NULL)
        fclose(bmp);

    bmp = fopen(filename.c_str(), "rb");
    if (bmp == NULL)
        printf("ファイルオープンに失敗しました。\n");

    readFileHeader();
    readInfoHeader();
    readBmpData();
}

ここのファイルオープンに失敗した時にprintfだけというのがまずいです。
とりあえず、ここにブレークポイントを設置してbmpNULLかを調べるとよいでしょう。


読み込み失敗した理由としては、カレントディレクトリが想定と違う事が考えられますので
getcwd関数で現在のカレントディレクトリを取得し確認してみるとよいでしょう。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/05/14 15:48

    bmpを確認してみましたがNULLでした

    まだまだ初心者でgetcwdについては調べてみます。すみません。

    キャンセル

checkベストアンサー

0

bmp.loadData("filename");
filenameという名前のファイルが存在しないと提示エラーが発生します。

なお、相対パス指定だと開始ディレクトリがどこだか考えるのが面倒なので
以下のようにフルパスで与えたほうが確実です。
"C:\\Users\\shinohara yuki\\source\\repos\\BMPcut\\ver5.14\\kii.bmp"

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/05/14 16:02

    ありがとうございます。
    解決しました。
    出力したファイルが開けない次のエラーが発生したので頑張ってみます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.80%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る