ページ 11

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

Posted: 2015年6月28日(日) 21:28
by ハイセ
こんばんは,初投稿です.よろしくお願いします.
今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ヶ月くらいです.
文章が読みづらい,コードが見づらい部分があると思いますが,どうかよろしくお願いします.

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

Posted: 2015年6月28日(日) 21:54
by みけCAT
ライセンス的に問題が無ければ、libpng (zlibに依存しています)を用いるのがいいと思います(Xcodeで使えるかはわかりませんが)。

↓参考
PNGファイル(2)  PNG操作の手順

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

Posted: 2015年6月28日(日) 22:03
by みけCAT
ライセンス的に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]

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

Posted: 2015年6月29日(月) 11:01
by ハイセ
みけCATさん,ありがとうございます.
そのようなライブラリは知りませんでした.
Xcodeでも使えるようなので,導入して試してみたいと思います.
ありがとうございました!

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

Posted: 2015年6月30日(火) 16:20
by ハイセ
何度も済みません.
以前の回答を元に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); 
}


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

Posted: 2015年6月30日(火) 17:03
by みけCAT
PNGや各チャンクのヘッダはzlibのデータではないので、inflateしようとするとエラーになることが容易に想像できます。
最初のプログラムではきちんとPNGのチャンク構造を考慮したプログラムになっていたようなのに、どうして劣化してしまったのでしょうか?

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

Posted: 2015年6月30日(火) 18:22
by ハイセ
みけCATさん,ありがとうございます.

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

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

Posted: 2015年6月30日(火) 20:22
by みけCAT
ハイセ さんが書きました:このようなコードになったのは,IHDRチャンクに圧縮形式の情報が入っているので,それを含めて読み込まないと
inflateが出来ないのではないか,と思ったのでこのようになりました.
IHDRの圧縮形式情報は、deflateなのか未知の形式なのかという情報しかありません。
deflateだとわかれば、後は不要です。
ハイセ さんが書きました:IDATチャンクだけでも読み込めるのでしょうか?
むしろIDATチャンクの中身のみ(名前、長さ、CRCも含めてはいけません)を渡さないとinflateできないはずです。

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

Posted: 2015年7月01日(水) 01:07
by ハイセ
なるほど,そういうことなんですね.誤解していました.
みけ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つの画像の差分画像の作成について

Posted: 2015年7月01日(水) 15:52
by ハイセ
済みません.先日質問した内容ですが,自己解決しました.
一度外部ファイルに保存し,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;
    
}


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

Posted: 2015年7月01日(水) 17:21
by みけCAT
175行目と178行目において、33バイトしか読み飛ばさないと、IDATチャンクがIHDRチャンクの直後にあったとしても、
IDATチャンクのヘッダが混ざってしまい、inflateに失敗すると思います。
PNG ファイルフォーマット

さらに、今回扱うデータがどうかはわかりませんが、一般のPNGファイルにおいてはIHDRチャンクの直後にIDATチャンクがあるとは限らないし、
IDATチャンクが複数ある場合もあります。

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

Posted: 2015年7月01日(水) 19:27
by ハイセ
確かにこれではIDATの始めの部分も含んでしまっていますね.修正します.

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

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

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

Posted: 2015年7月01日(水) 21:18
by ハイセ
今調べて見たのですが,複数のIDATチャンクがあり
おそらく1つ目のIDATチャンク→2つ目のIDATチャンク・・・といったように配置されているようです.

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

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

Posted: 2015年7月01日(水) 21:41
by みけCAT
ハイセ さんが書きました: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の関数に渡すようにプログラムを書けば良いと思います。

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

Posted: 2015年7月02日(木) 01:06
by ハイセ
いろいろ調べて頂いてありがとうございます.参考にします.

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

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

Posted: 2015年7月02日(木) 10:16
by ハイセ
済みません,もうひとつ聞きたいのですが,
avail_inの読み込みもヘッダを除いたほうが良いですよね?

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

Posted: 2015年7月02日(木) 10:33
by みけCAT
ハイセ さんが書きました:avail_inの読み込みもヘッダを除いたほうが良いですよね?
PNG(チャンクを含む)のヘッダは除くべきですが、ZLIBのヘッダは除いてはいけません。

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

Posted: 2015年7月02日(木) 12:44
by ハイセ
つまり,IDATチャンクの画像データ以外は読み飛ばして良いということでしょうか?

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

Posted: 2015年7月02日(木) 13:15
by みけCAT
ハイセ さんが書きました:つまり,IDATチャンクの画像データ以外は読み飛ばして良いということでしょうか?
画像を読み取るのではなく、ただinflateしてみるのが目的なら、いいです。

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

Posted: 2015年7月02日(木) 14:49
by ハイセ
なるほど・・分かりました.
プログラムを書きなおしてみます.