2つの画像の差分画像の作成について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ハイセ

2つの画像の差分画像の作成について

#1

投稿記事 by ハイセ » 10年前

こんばんは,初投稿です.よろしくお願いします.
今C言語で2つの画像(両方グレースケール)を読み込み,その差分画像を出力するプログラムを作成しているのですが,差分画像を上手く出力することが出来ず苦戦しています.書いたコードは以下になります.

コード:

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>

#define WSIZE 2400/*元データの横サイズ*/
#define HSIZE 2000/*元データの縦サイズ*/
#define size 2400*2000

#define hdsize 37 //ヘッダの長さ+CRCの長さ

unsigned char PNGsig[8]={0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A};
unsigned char IHDR[4]={0x49,0x48,0x44,0x52};
unsigned char IDAT[4]={0x49,0x44,0x41,0x54};
unsigned char IEND[4]={0x49,0x45,0x4E,0x44};

unsigned char buf1[size];
unsigned char buf2[size];

unsigned char image1[size];
unsigned char image2[size];
unsigned char image3[size];

unsigned char header1[hdsize];
unsigned char header2[hdsize];

unsigned char IDATs1[4];
unsigned char IDATs2[4];

unsigned char IDATCRC1[4];
unsigned char IDATCRC2[4];

unsigned char IEND1[12];
unsigned char IEND2[12];


void image_input(); 

int main(){
    
    image_input();
    
}


void image_input(){
	FILE *fp1,*fp2,*fp3;
	int l,k,i;
    //画像ファイルの読み込み
    char *filename1="basegray.png";
    char *filename2="dst_gaus.png";
    char *filename3="abcd.png";
    
	fp1 = fopen(filename1, "rb");
    fread(buf1, sizeof(unsigned char), sizeof(buf1) ,fp1);
    fp2 = fopen(filename2, "rb");
	fread(buf2, sizeof(unsigned char), sizeof(buf2) ,fp2);
    
    //PNGシグネチャの確認
    if(memcmp(PNGsig,buf1,8)==0 &&
       memcmp(PNGsig,buf2,8)==0){
        printf("pngファイルです");
    }else{
        printf("pngファイルではありません\n");
        exit(1);
    }
    
    //ヘッダを取り出し
    for(i=0;i<sizeof(header1);i++){
        header1[i]=buf1[i];
        header2[i]=buf2[i];
        //printf("%d,",header1[i]);
    }
    
    
    //IDATの取り出し
    for(i=0;i<4;i++){
        if(IDAT[i]-buf1[i+hdsize]==0 &&
           IDAT[i]-buf2[i+hdsize]==0){
            IDATs1[i]=buf1[i+hdsize];
            IDATs2[i]=buf2[i+hdsize];
            //printf("%d,",IDATs1[i]);
        }
    }
    
    //画像データ開始位置の確認
    if(memcmp(IDAT,IDATs1,4)==0 &&
       memcmp(IDAT,IDATs2,4)==0){
        printf("画像データの確認");
    }else{
        printf("画像データの確認ができません\n");
        exit(1);
    }
    
    

    //IENDの位置確認
    for(i=0;i<sizeof(buf1);i++){
        image1[i]=buf1[i+42];
        
        if(IEND[3]-image1[i]==0 &&
           IEND[2]-image1[i-1]==0 &&
           IEND[1]-image1[i-2]==0 &&
           IEND[0]-image1[i-3]==0){
            printf("終わり");
            IDATCRC1[0]=image1[i-11];
            IDATCRC1[1]=image1[i-10];
            IDATCRC1[2]=image1[i-9];
            IDATCRC1[3]=image1[i-8];
            IEND1[0]=image1[i-7];
            IEND1[1]=image1[i-6];
            IEND1[2]=image1[i-5];
            IEND1[3]=image1[i-4];
            IEND1[4]=image1[i-3];
            IEND1[5]=image1[i-2];
            IEND1[6]=image1[i-1];
            IEND1[7]=image1[i];
            IEND1[8]=image1[i+1];
            IEND1[9]=image1[i+2];
            IEND1[10]=image1[i+3];
            IEND1[11]=image1[i+4];
            
            k=i;
            //printf("%d",k);
            
            break;
        }
    }
    
    for(i=0;i<sizeof(buf2);i++){
        image2[i]=buf2[i+41];
        
        if(IEND[3]-image2[i]==0 &&
           IEND[2]-image2[i-1]==0 &&
           IEND[1]-image2[i-2]==0 &&
           IEND[0]-image2[i-3]==0){
            printf("終わり");
            IDATCRC2[0]=image2[i-11];
            IDATCRC2[1]=image2[i-10];
            IDATCRC2[2]=image2[i-9];
            IDATCRC2[3]=image2[i-8];
            IEND2[0]=image2[i-7];
            IEND2[1]=image2[i-6];
            IEND2[2]=image2[i-5];
            IEND2[3]=image2[i-4];
            IEND2[4]=image2[i-3];
            IEND2[5]=image2[i-2];
            IEND2[6]=image2[i-1];
            IEND2[7]=image2[i];
            IEND2[8]=image2[i+1];
            IEND2[9]=image2[i+2];
            IEND2[10]=image2[i+3];
            IEND2[11]=image2[i+4];
            
            l=i;
            //printf("%d,",l);
            break;
        }
    }
    
    //差分計算
   //この部分の計算が上手くいかない
    for(i=1;i<l;i++){
        image3[i]=abs(image1[i]-image2[i]);
        
        //printf("%x,",image3[i]);
        //image1[i]=image3[i];
    }
     
    /*
    fp3 = fopen(filename3, "wb");
	fwrite(buf1, sizeof(unsigned char), 42 ,fp3);
    fwrite(image1, sizeof(unsigned char), k ,fp3);
    fwrite(IDATCRC1,sizeof(unsigned char),4,fp3);
    fwrite(IEND1, sizeof(unsigned char), sizeof(IEND1) ,fp3);
    
    
    fp4 = fopen(filename4, "wb");
	fwrite(buf2, sizeof(unsigned char), sizeof(buf2) ,fp4);
    */
}

画像は読み込めていることは確認済み,またチャンクの読み込みも正しく出来ているようです.
画像データはIDATチャンクに入ってるので,それの差分で作成出来るのではないか,と考えていたのですがどうも上手く行きません.どのようにすれば良いか検討がつかない状態なので,教えていただけないでしょうか?
OSはMAC OS10.7.5,環境はXcode4.5で,c言語は始めてだいたい2ヶ月〜3ヶ月くらいです.
文章が読みづらい,コードが見づらい部分があると思いますが,どうかよろしくお願いします.

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: 2つの画像の差分画像の作成について

#2

投稿記事 by みけCAT » 10年前

ライセンス的に問題が無ければ、libpng (zlibに依存しています)を用いるのがいいと思います(Xcodeで使えるかはわかりませんが)。

↓参考
PNGファイル(2)  PNG操作の手順
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: 2つの画像の差分画像の作成について

#3

投稿記事 by みけCAT » 10年前

ライセンス的にlibpngは使えない、Xcodeがlibpngに対応していない、勉強のため標準でないライブラリには頼りたくない、課題のため標準ライブラリしか使えない、などの事情があるのであれば、
真面目にzlib(+deflate)形式とPNGで用いられる形式のデータのデコードを行い、画像の差分を取り、
再びPNGで用いられる形式のデータへのエンコードとzlib形式へのエンコード(書き込みは凝らずに色をそのまま出力するフィルタのみを使用+無圧縮でもいいので比較的楽です)をするのがいいでしょう。

ZLIB Compressed Data Format Specification
DEFLATE Compressed Data Format Specification version 1.3
[search=google]IDAT デコード[/search]
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ハイセ

Re: 2つの画像の差分画像の作成について

#4

投稿記事 by ハイセ » 10年前

みけCATさん,ありがとうございます.
そのようなライブラリは知りませんでした.
Xcodeでも使えるようなので,導入して試してみたいと思います.
ありがとうございました!

ハイセ

Re: 2つの画像の差分画像の作成について

#5

投稿記事 by ハイセ » 10年前

何度も済みません.
以前の回答を元にpnglibを用いてプログラムを組もうとしたのですが,関数が多く良くわからなくなってしまったので,
zlibを使ってプログラムを組むことにしました.
方針としては,「2つの画像データをinflate→展開した画像データを使って差分を計算→deflateして元に戻す」というように
考えています.
以下は画像をinflateするコードなのですが,最初のinflateでエラーになってしまいました.おそらく書き方を間違えていると思うのですが,どこで間違えているか見ていただけませんでしょうか?よろしくお願いします.
(警告などは出ていません)
(下記のコードは
 http://x768.com/w/zlib.en
 http://oku.edu.mie-u.ac.jp/~okumura/com ... comptest.c
 http://www.tnksoft.com/reading/zipfile/comp2.php
を参考に作成しました)

コード:


#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <png.h>
#include <zlib.h>
#include <zconf.h>

#define inbufsize 2048
#define outbufsize 2048

unsigned char inbuf[inbufsize];
unsigned char outbuf[outbufsize];

void image_inflate();
//void image_out();

int main(){
    
    image_inflate();
    
}

void image_inflate(){
    
    FILE *fp1,*fp2;
   //取り敢えず画像をinflate出来るか確認
    char *filename1="basegray.png"; 
    char *filename2="basegray_1.png";
 
    int status;
    int flashtype;
    int buffer=0;
    int count;
    //int rest;
    
    //zlib構造体の初期化
    z_stream z;
    z.zalloc=Z_NULL;
    z.zfree=Z_NULL;
    z.opaque=Z_NULL;
    
    z.next_in=Z_NULL;
    z.avail_in=0;
    z.next_out=outbuf;
    z.avail_out=outbufsize;
    status=Z_OK;
    
    if(inflateInit(&z)!=Z_OK){
        printf("初期化に失敗しました");
        exit(1);
    }
    fp1=fopen(filename1,"rb");
    fp2=fopen(filename2,"wb");
    
    //終わるまで読み込む
    while(status!=Z_STREAM_END){
        if(z.avail_in==0){
            z.next_in=inbuf;
            z.avail_in=fread(inbuf,sizeof(unsigned char),inbufsize,fp1);
        }
        //画像を展開
        status=inflate(&z,Z_NO_FLUSH);
        
        if(status==Z_STREAM_END){
            printf("終了\n");
            break;
        }

        //はじめにここに入ってしまい,エラーになる
        if(status!=Z_OK){
            printf("error\n");
            fclose(fp1);
            fclose(fp2);
            return;
            break;
        }
        //バッファが0になったら,元に戻す
        if(z.avail_out==0){
            if(fwrite(outbuf,sizeof(unsigned char),outbufsize,fp2)!=outbufsize){
                
                printf("error\n");
                fclose(fp1);
                fclose(fp2);
                break;
            }
                z.next_out=outbuf;
                z.avail_out=outbufsize;
        }
    }

    if((count=z.avail_out-outbufsize)!=0){
        if(fwrite(outbuf,sizeof(unsigned char),count,fp2)!=count){
            printf("error\n");
            fclose(fp1);
            fclose(fp2);
        }
    }
    
    if(inflateEnd(&z)!=0){
        printf("error\n");
        fclose(fp1);
        fclose(fp2);
    }
    
    fclose(fp1);
    fclose(fp2); 
}


アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: 2つの画像の差分画像の作成について

#6

投稿記事 by みけCAT » 10年前

PNGや各チャンクのヘッダはzlibのデータではないので、inflateしようとするとエラーになることが容易に想像できます。
最初のプログラムではきちんとPNGのチャンク構造を考慮したプログラムになっていたようなのに、どうして劣化してしまったのでしょうか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ハイセ

Re: 2つの画像の差分画像の作成について

#7

投稿記事 by ハイセ » 10年前

みけCATさん,ありがとうございます.

このようなコードになったのは,IHDRチャンクに圧縮形式の情報が入っているので,それを含めて読み込まないと
inflateが出来ないのではないか,と思ったのでこのようになりました.
IDATチャンクだけでも読み込めるのでしょうか?

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: 2つの画像の差分画像の作成について

#8

投稿記事 by みけCAT » 10年前

ハイセ さんが書きました:このようなコードになったのは,IHDRチャンクに圧縮形式の情報が入っているので,それを含めて読み込まないと
inflateが出来ないのではないか,と思ったのでこのようになりました.
IHDRの圧縮形式情報は、deflateなのか未知の形式なのかという情報しかありません。
deflateだとわかれば、後は不要です。
ハイセ さんが書きました:IDATチャンクだけでも読み込めるのでしょうか?
むしろIDATチャンクの中身のみ(名前、長さ、CRCも含めてはいけません)を渡さないとinflateできないはずです。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ハイセ

Re: 2つの画像の差分画像の作成について

#9

投稿記事 by ハイセ » 10年前

なるほど,そういうことなんですね.誤解していました.
みけCATさんの助言を元にコードを書き直しました.

この場合freadが使えないため,avail_inへのデータの渡し方をfor文で考えたのですが
これだと上手く渡せていないようです.
inbuf分だけデータを読み込み,avail_inに渡すにはどのようにしたら良いでしょうか?

コード:

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <png.h>
#include <zlib.h>
#include <zconf.h>

#define WSIZE 2400/*元データの横サイズ*/
#define HSIZE 2000/*元データの縦サイズ*/
#define size 2400*2000
#define inbufsize 4096
#define outbufsize 4096

#define hdsize 37 //ヘッダの長さ+CRCの長さ

unsigned char inbuf[inbufsize];
unsigned char outbuf[outbufsize];

unsigned char PNGsig[8]={0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A};
unsigned char IHDR[4]={0x49,0x48,0x44,0x52};
unsigned char IDAT[4]={0x49,0x44,0x41,0x54};
unsigned char IEND[4]={0x49,0x45,0x4E,0x44};

unsigned char buf1[size];
unsigned char buf2[size];
unsigned char buf3[size];
unsigned char buf4[size];

unsigned char header1[hdsize];
unsigned char header2[hdsize];

unsigned char IDATs1[4];
unsigned char IDATs2[4];

/*画像データが入ってる配列*/
void image_input(int *k,int *l); 
void image_inflate(int *k,int *l);

int main(){
    
    int l,k;  //画像データ+IEND(CRC含まない)までの長さ
    
    image_input(&l,&k);
    
    image_inflate(&l,&k);
        
}


void image_input(int *k,int *l){
        
	FILE *fp1,*fp2;
	int i;
    
    //int o,p;
    char *filename1="basegray.png";
    char *filename2="dst_gaus.png";
    
	/*画像ファイルの読み込み*/
	fp1 = fopen(filename1, "rb");
    fread(buf1, sizeof(unsigned char), sizeof(buf1) ,fp1);
    //printf("%d",l);
    fp2 = fopen(filename2, "rb");
	fread(buf2, sizeof(unsigned char), sizeof(buf2) ,fp2);
    
    //シグネチャの確認
    if(memcmp(PNGsig,buf1,8)==0 &&
       memcmp(PNGsig,buf2,8)==0){
        printf("pngファイルです");
    }else{
        printf("pngファイルではありません\n");
        exit(1);
    }
    
    //ヘッダを取り出し
    for(i=0;i<sizeof(header1);i++){
        header1[i]=buf1[i];
        header2[i]=buf2[i];
        //printf("%d,",header1[i]);
    }
    
    
    //IDATの取り出し
    for(i=0;i<4;i++){
        if(IDAT[i]-buf1[i+hdsize]==0 &&
           IDAT[i]-buf2[i+hdsize]==0){
            IDATs1[i]=buf1[i+hdsize];
            IDATs2[i]=buf2[i+hdsize];
            //printf("%d,",IDATs1[i]);
        }
    }
    
    //画像データ開始位置の確認
    if(memcmp(IDAT,IDATs1,4)==0 &&
       memcmp(IDAT,IDATs2,4)==0){
        printf("画像データの確認");
    }else{
        printf("画像データの確認ができません\n");
        exit(1);
    }
    

    //IENDの位置確認,画像データの長さ確認
    for(i=0;i<sizeof(buf1);i++){
        //image1[i]=buf1[i+41];
        
        if(IEND[3]-buf1[i+41]==0 &&
           IEND[2]-buf1[(i+41)-1]==0 &&
           IEND[1]-buf1[(i+41)-2]==0 &&
           IEND[0]-buf1[(i+41)-3]==0){
            printf("終わり");
            *k=i;
            //printf("%d",*k);
            break;
        }
    }
    
    for(i=0;i<sizeof(buf2);i++){
        //image2[i]=buf2[i+41];
        
        if(IEND[3]-buf2[i+41]==0 &&
           IEND[2]-buf2[(i+41)-1]==0 &&
           IEND[1]-buf2[(i+41)-2]==0 &&
           IEND[0]-buf2[(i+41)-3]==0){
            printf("終わり");
            *l=i;
            //printf("%ld,",*l);
            break;
        }
    }
    
    
    fclose(fp1);
    fclose(fp2);
    
    /* 
    fp3 = fopen(filename3, "wb");
	fwrite(buf1, sizeof(unsigned char), 41 ,fp3);
    fwrite(image1, sizeof(unsigned char), k ,fp3);
    fwrite(IDATCRC1,sizeof(unsigned char),4,fp3);
    fwrite(IEND1, sizeof(unsigned char), sizeof(IEND1) ,fp3);
    
 
    fp4 = fopen(filename4, "wb");
	fwrite(buf2, sizeof(unsigned char), sizeof(buf2) ,fp4);
    */
}

void image_inflate(int *k,int *l){
    //動作確認のため,IDATALL1のみを使う
    unsigned char IDATALL1[*k-8];
    unsigned char IDATALL2[*l-8];
    int j;
    int m=0,n=0;
    
    int status;
    int flashtype;
    int buffer=0;
    int count;
    
    //IDATデータをすべてまとめる
    //33はヘッダー部分
    //-8は,IENDの頭が余分にあるため,それを考慮して書き込むため
    //IDATのCRCまで読み込む
    
    for(j=0;j<*k-8;j++){
        IDATALL1[j]=buf1[j+33];
    }
    for(j=0;j<*l-8;j++){
        IDATALL2[j]=buf2[j+33];
    }
    
    //printf("%ld",sizeof(IDATALL1));
    //IDATを使用してinflate展開する
    
    //構造体の初期化
    z_stream z;
    z.zalloc=Z_NULL;
    z.zfree=Z_NULL;
    z.opaque=Z_NULL;
    
    z.next_in=Z_NULL;
    z.avail_in=0;
    z.next_out=outbuf;
    z.avail_out=outbufsize;
    status=Z_OK;
    
    if(inflateInit(&z)!=Z_OK){
        printf("初期化に失敗しました");
        exit(1);
    }
     
    while(status!=Z_STREAM_END){
        if(z.avail_in==0){
            z.next_in=inbuf;
            //z.avail_in=sizeof(inbuf);
            //mの分だけ配列初期位置を進める
            for(j=sizeof(inbuf)*m ; j<sizeof(inbuf)+(sizeof(inbuf))*m ; j++){
                
                inbuf[j]=IDATALL1[j];
                
            }
            m++;
            
        }
            //入力バッファに入れる
            z.avail_in=sizeof(inbuf);
             
            //fread(inbuf,sizeof(unsigned char),inbufsize,fp3);
        
        //printf("%d",j);
        
        status=inflate(&z,Z_NO_FLUSH);
        
        if(status==Z_STREAM_END){
            printf("終了\n");
            break;
        }
        
        //はじめにここに入ってしまう
        //エラーは,他のチャンクがzlibに対応していないため
        //IDATチャンクのみを使う
        
        if(status!=Z_OK){
            printf("error\n");
            return;
            break;
        }
        //buf3にデータを移す
        
        if(z.avail_out==0){
            
            if(sizeof(outbuf)!=outbufsize){
                printf("error\n");
                break;
            }
            
            for(j=(sizeof(outbuf))*n;j<sizeof(outbuf)+(sizeof(outbuf))*n;j++){
                buf3[j]=outbuf[j];
            }
            
            n++;
            
            z.next_out=outbuf;
            z.avail_out=outbufsize;
        }
         
    }
    //
    
    if((count=z.avail_out-outbufsize)!=0){
          if(sizeof(outbuf)!=outbufsize){
            printf("error\n");
    }
}
    
    if(inflateEnd(&z)!=0){
        printf("error\n");
    }
    
    
}


ハイセ

Re: 2つの画像の差分画像の作成について

#10

投稿記事 by ハイセ » 10年前

済みません.先日質問した内容ですが,自己解決しました.
一度外部ファイルに保存し,freadでinbufごとにデータを読み込む方法を行うことにしました.
以下がそのコードです.

しかし,これでもやはり同じ場所でエラーになってしまいます.
ここからどのように書き換えた方が良いでしょうか?
よろしくお願いします.

コード:

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <png.h>
#include <zlib.h>
#include <zconf.h>

#define WSIZE 2400/*元データの横サイズ*/
#define HSIZE 2000/*元データの縦サイズ*/
#define size 2400*2000
#define inbufsize 4096
#define outbufsize 4096

#define hdsize 37 //ヘッダの長さ+CRCの長さ

unsigned char inbuf[inbufsize];
unsigned char outbuf[outbufsize];

unsigned char PNGsig[8]={0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A};
unsigned char IHDR[4]={0x49,0x48,0x44,0x52};
unsigned char IDAT[4]={0x49,0x44,0x41,0x54};
unsigned char IEND[4]={0x49,0x45,0x4E,0x44};

unsigned char buf1[size];
unsigned char buf2[size];
unsigned char buf3[size];
unsigned char buf4[size];

unsigned char header1[hdsize];
unsigned char header2[hdsize];

unsigned char IDATs1[4];
unsigned char IDATs2[4];

void image_input(int *k,int *l); 
void image_inflate(int *k,int *l);

int main(){
    
    int l,k;
    
    image_input(&l,&k);
    
    image_inflate(&l,&k);
    
}


void image_input(int *k,int *l){
    
	FILE *fp1,*fp2;
	int i;
    
    //int o,p;
    char *filename1="basegray.png";
    char *filename2="dst_gaus.png";
    
	/*画像ファイルの読み込み*/
	fp1 = fopen(filename1, "rb");
    fread(buf1, sizeof(unsigned char), sizeof(buf1) ,fp1);
    //printf("%d",l);
    fp2 = fopen(filename2, "rb");
	fread(buf2, sizeof(unsigned char), sizeof(buf2) ,fp2);
    
    //シグネチャの確認
    if(memcmp(PNGsig,buf1,8)==0 &&
       memcmp(PNGsig,buf2,8)==0){
        printf("pngファイルです");
    }else{
        printf("pngファイルではありません\n");
        exit(1);
    }
    
    //ヘッダを取り出し
    for(i=0;i<sizeof(header1);i++){
        header1[i]=buf1[i];
        header2[i]=buf2[i];
        //printf("%d,",header1[i]);
    }
    
    
    //IDATの取り出し
    for(i=0;i<4;i++){
        if(IDAT[i]-buf1[i+hdsize]==0 &&
           IDAT[i]-buf2[i+hdsize]==0){
            IDATs1[i]=buf1[i+hdsize];
            IDATs2[i]=buf2[i+hdsize];
            //printf("%d,",IDATs1[i]);
        }
    }
    
    //画像データ開始位置の確認
    if(memcmp(IDAT,IDATs1,4)==0 &&
       memcmp(IDAT,IDATs2,4)==0){
        printf("画像データの確認");
    }else{
        printf("画像データの確認ができません\n");
        exit(1);
    }
    
    
    //IENDの位置確認,画像データの長さ確認
    for(i=0;i<sizeof(buf1);i++){
        //image1[i]=buf1[i+41];
        
        if(IEND[3]-buf1[i+41]==0 &&
           IEND[2]-buf1[(i+41)-1]==0 &&
           IEND[1]-buf1[(i+41)-2]==0 &&
           IEND[0]-buf1[(i+41)-3]==0){
            printf("終わり");
            *k=i;
            //printf("%d",*k);
            break;
        }
    }
    
    for(i=0;i<sizeof(buf2);i++){
        //image2[i]=buf2[i+41];
        
        if(IEND[3]-buf2[i+41]==0 &&
           IEND[2]-buf2[(i+41)-1]==0 &&
           IEND[1]-buf2[(i+41)-2]==0 &&
           IEND[0]-buf2[(i+41)-3]==0){
            printf("終わり");
            *l=i;
            //printf("%ld,",*l);
            break;
        }
    }
    
    
    fclose(fp1);
    fclose(fp2);
    
    /* 
     fp3 = fopen(filename3, "wb");
     fwrite(buf1, sizeof(unsigned char), 41 ,fp3);
     fwrite(image1, sizeof(unsigned char), k ,fp3);
     fwrite(IDATCRC1,sizeof(unsigned char),4,fp3);
     fwrite(IEND1, sizeof(unsigned char), sizeof(IEND1) ,fp3);
     
     
     fp4 = fopen(filename4, "wb");
     fwrite(buf2, sizeof(unsigned char), sizeof(buf2) ,fp4);
     */
}

void image_inflate(int *k,int *l){
    
    unsigned char IDATALL1[*k-8];
    unsigned char IDATALL2[*l-8];
    int i,j;
    int m=0,n=0;
    
    int status;
    int flashtype;
    int buffer=0;
    int count;
    
    FILE *fp3,*fp4;
    FILE *fp5,*fp6;
    FILE *fp7,*fp8;
    char *filename3="test1.dat";
    char *filename4="test2.dat";
    char *filename5="inflate1.dat";
    char *filename6="inflate2.dat";
    
    //IDATデータをすべてまとめる
    //33はヘッダー部分
    //-8は,IENDの頭が余分にあるため,それを考慮して書き込むため
    //IDATのCRCまで読み込む
    
    for(j=0;j<*k-8;j++){
        IDATALL1[j]=buf1[j+33];
    }
    for(j=0;j<*l-8;j++){
        IDATALL2[j]=buf2[j+33];
    }
    
    //一時外部ファイルに保存(freadを使用するため)
    fp3=fopen(filename3,"wb");
    fwrite(IDATALL1,sizeof(unsigned char),sizeof(IDATALL1),fp3);
    fclose(fp3);
    
    fp4=fopen(filename4,"wb");
    fwrite(IDATALL2,sizeof(unsigned char),sizeof(IDATALL2),fp4);
    fclose(fp4);
    
    //printf("%ld",sizeof(IDATALL1));
    //IDATを使用してinflate展開する
    
    //構造体の初期化
    z_stream z;
    z.zalloc=Z_NULL;
    z.zfree=Z_NULL;
    z.opaque=Z_NULL;
    
    z.next_in=Z_NULL;
    z.avail_in=0;
    z.next_out=outbuf;
    z.avail_out=outbufsize;
    status=Z_OK;
    
    fp5=fopen(filename3,"rb");
    fp6=fopen(filename4,"rb");
    fp7=fopen(filename5,"wb");
    fp8=fopen(filename6,"wb");
    
    if(inflateInit(&z)!=Z_OK){
        printf("初期化に失敗しました");
        exit(1);
    }
    
    while(status!=Z_STREAM_END){
        if(z.avail_in==0){
            z.next_in=inbuf;
            z.avail_in=fread(inbuf,sizeof(unsigned char),sizeof(inbuf),fp5);
        }
                
        status=inflate(&z,Z_NO_FLUSH);
        
        if(status==Z_STREAM_END){
            printf("終了\n");
            break;
        }
        //この部分でやはりエラーになってしまう
        if(status!=Z_OK){
            printf("error\n");
            fclose(fp5);
            fclose(fp7);
            break;
        }
        
        if(z.avail_out==0){
            
            if(fwrite(outbuf,sizeof(unsigned char),sizeof(outbuf),fp7)!=outbufsize){
                printf("error\n");
                fclose(fp5);
                fclose(fp7);

                break;
            }
            
            z.next_out=outbuf;
            z.avail_out=outbufsize;
        }
        
    }
    //
    
    if((count=outbufsize-z.avail_out)!=0){
        if(sizeof(outbuf)!=outbufsize){
            printf("error\n");
            fclose(fp5);
            fclose(fp7);

        }
    }
    
    if(inflateEnd(&z)!=0){
        printf("error\n");
        fclose(fp5);
        fclose(fp7);

    }
    
    fclose(fp5);
    fclose(fp7);
    return;
    
}


アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: 2つの画像の差分画像の作成について

#11

投稿記事 by みけCAT » 10年前

175行目と178行目において、33バイトしか読み飛ばさないと、IDATチャンクがIHDRチャンクの直後にあったとしても、
IDATチャンクのヘッダが混ざってしまい、inflateに失敗すると思います。
PNG ファイルフォーマット

さらに、今回扱うデータがどうかはわかりませんが、一般のPNGファイルにおいてはIHDRチャンクの直後にIDATチャンクがあるとは限らないし、
IDATチャンクが複数ある場合もあります。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ハイセ

Re: 2つの画像の差分画像の作成について

#12

投稿記事 by ハイセ » 10年前

確かにこれではIDATの始めの部分も含んでしまっていますね.修正します.

今回はグレースケール画像を扱っており,IHDRの直後にIDATが確認出来ているので,
おそらく問題はないと考えています.ただ,今後エラー処理を入れる上でPLTEチャンクの処理などは必要になると思うので,
いずれプログラムを書きたいと思っています.

IDATチャンクが複数あるというのは,1つ目のIDAT→2つ目のIDATのように規則正しく並んでいるのでしょうか?
それとも画像データの途中などで唐突に出てくるものなのでしょうか?

ハイセ

Re: 2つの画像の差分画像の作成について

#13

投稿記事 by ハイセ » 10年前

今調べて見たのですが,複数のIDATチャンクがあり
おそらく1つ目のIDATチャンク→2つ目のIDATチャンク・・・といったように配置されているようです.

各チャンクをヘッダ部分を除いて順番にinflateしたいのですが,どのようにプログラムを書けば良いでしょうか?

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: 2つの画像の差分画像の作成について

#14

投稿記事 by みけCAT » 10年前

ハイセ さんが書きました:IDATチャンクが複数あるというのは,1つ目のIDAT→2つ目のIDATのように規則正しく並んでいるのでしょうか?
それとも画像データの途中などで唐突に出てくるものなのでしょうか?
IDATは連続して並んでいるはずです。
複数のIDATチャンクは連続的であるべきです
(Portable Network Graphics(PNG)仕様 第2版 日本語訳 - 5.6 チャンク順序)
Multiple IDAT chunks shall be consecutive
(Portable Network Graphics (PNG) Specification (Second Edition) - 5.6 Chunk ordering)
複数のIDATチャンクがあるかもしれません。もしそうであれば、それらは他のチャンクがその間に入ることなく連続的に現れます。 圧縮データストリームは、すべてのIDATチャンクのデータフィールドの内容を連結したものです。
(Portable Network Graphics(PNG)仕様 第2版 日本語訳 - 11.2.4 IDAT イメージデータ)
There may be multiple IDAT chunks; if so, they shall appear consecutively with no other intervening chunks. The compressed datastream is then the concatenation of the contents of the data fields of all the IDAT chunks.
(Portable Network Graphics (PNG) Specification (Second Edition) - 11.2.4 IDAT Image data)
ハイセ さんが書きました:各チャンクをヘッダ部分を除いて順番にinflateしたいのですが,どのようにプログラムを書けば良いでしょうか?
各チャンクを長さ情報に従って順番に見ていき、IDATだったらデータをinflateの関数に渡すようにプログラムを書けば良いと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ハイセ

Re: 2つの画像の差分画像の作成について

#15

投稿記事 by ハイセ » 10年前

いろいろ調べて頂いてありがとうございます.参考にします.

ありがとうございます.そのようにプログラムを書き換えてみます.

ハイセ

Re: 2つの画像の差分画像の作成について

#16

投稿記事 by ハイセ » 10年前

済みません,もうひとつ聞きたいのですが,
avail_inの読み込みもヘッダを除いたほうが良いですよね?

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: 2つの画像の差分画像の作成について

#17

投稿記事 by みけCAT » 10年前

ハイセ さんが書きました:avail_inの読み込みもヘッダを除いたほうが良いですよね?
PNG(チャンクを含む)のヘッダは除くべきですが、ZLIBのヘッダは除いてはいけません。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ハイセ

Re: 2つの画像の差分画像の作成について

#18

投稿記事 by ハイセ » 10年前

つまり,IDATチャンクの画像データ以外は読み飛ばして良いということでしょうか?

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: 2つの画像の差分画像の作成について

#19

投稿記事 by みけCAT » 10年前

ハイセ さんが書きました:つまり,IDATチャンクの画像データ以外は読み飛ばして良いということでしょうか?
画像を読み取るのではなく、ただinflateしてみるのが目的なら、いいです。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ハイセ

Re: 2つの画像の差分画像の作成について

#20

投稿記事 by ハイセ » 10年前

なるほど・・分かりました.
プログラムを書きなおしてみます.

閉鎖

“C言語何でも質問掲示板” へ戻る