Chinaunix首页 | 论坛 | 博客
  • 博客访问: 813101
  • 博文数量: 296
  • 博客积分: 5376
  • 博客等级: 大校
  • 技术积分: 2298
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-14 19:02
文章分类

全部博文(296)

文章存档

2023年(2)

2020年(2)

2018年(2)

2017年(26)

2016年(4)

2015年(19)

2014年(12)

2013年(26)

2012年(84)

2011年(50)

2010年(41)

2009年(28)

分类:

2009-06-14 18:54:38

因为考虑用硬件做一个JPEG的编码器,所以需要对原始的RGB图像数据进行处理。前段时间看了不少关于JPEG编解码和DCT变换的paper,软件的模型基本上已经建立起来,接下来的工作就是要在Soc Designer上进行系统的建模,并把图像编码部分做成一个硬件加速的IP核。话题偏离了,呵呵。所有这些工作都需要原始图像的RGB数据进行输入,所以昨天写了一个解析bmp文件的perl程序。
      该perl程序接受一个参数,即需要parse的bmp文件名(目前只支持24-bit bmp格式),然后将会在屏幕上打印出bmp文件头信息,并将RGB数据保存在txt的文本文件里面。另外,因为在做DCT变换之前需要进行颜色空间的转换RGB->YCbCr,所以该程序中还进行了RGB到YCbCr的转换,并将YCbCr信息也输出到txt文件中。
      其实我觉得这个程序用python来写的话或许会更好一点,不过我很喜欢perl的正则表达式。其中有几个问题是需要注意的:
      1.对bmp文件读入后需要用binmode来转换成二进制格式,另外还需要用unpack函数来转换我们需要的格式。关于unpack函数,可以参考perlfunc或者google之;
      2.在对bmp文件进行读入的时候,十六进制的"0A"会被认为是换行符'\n',所以如果RGB数据中存在"0A"数据,<>操作符会停止,所以有可能所有数据并未全部读入,需要在后面进行继续读入所有数据;
      3.同样是"0A"字符带来的问题。我们一般对读入的每一行都采取一个chomp操作将末尾的换行符去掉,但是在bmp文件中,千万不能使用chomp函数,因为这里的"0A"并未真正的换行符,而是有效数据。我开始就是这样,不知道为什么,总是差一个数据,搞了很久才发现这个问题。
      4.bmp文件中的RGB数据是按最后一行到第一行的顺序来存储的,所以将所有RGB数据读入后,需要进行顺序的调整,请参考bmp文件格式。

      源代码如下:

#!/usr/bin/perl -w

# ---------------------------------------------------------

# parse bmp file to get RGB information

# by Tao Yuliang

# 28/03/2009

# ---------------------------------------------------------

#

#use strict;


# prepare

my @bmp_tag = qw(
                        bfType
                        bfSize
                        bfReserved1
                        bfReserved2
                        bfOffBits
                        biSize
                        biWidth
                        biHeight
                        biPlanes
                        biBitCount
                        biCompression
                        biSizeImage
                        biXPelsPerMeter
                        biYPelsPerMeter
                        biClrUsed
                        biClrImportant
                    );

binmode STDIN;
binmode STDOUT;

my $data_format = "H";

#------------------------------------------#

# read the bmp file and parse the data #

#------------------------------------------#

# get the file name

die "No input file!\n" if not $filename = shift @ARGV;
# open the file

open RGBFILE, $filename
    or die "Can't open $filename: $!";
binmode RGBFILE;

# read the bmp file

my $data = <RGBFILE> ;

# convert the data into a certain format

# to get the information of bmp file

#my @hdr_dat = unpack "SLSSLLLLSSLLLLLLC*", $data;

my @hdr_dat = unpack "SLSSLLLLSSLLLLLL$data_format*", $data;
$hdr_dat[0] = join '', unpack "aa", $data;
#print "@hdr_dat\n";


# get the image data form $hdr_dat[-1]

my @rgb_data;
for ( 1..($#hdr_dat-$#bmp_tag) ) {

        unshift @rgb_data, pop @hdr_dat;
}
#print "@hdr_dat\n";

#print "@rgb_data\n";


# if there is '0A' data in image data, perl will treate it as a '\n'

# so we must read the remaining data

while ( <RGBFILE> ) {
        # don't chomp, else it will discards '0A'

        #chomp ;

        push @rgb_data, unpack "$data_format*", $_;
}
close RGBFILE;

# store the info of file structure into a hash

my %header;
@header{@bmp_tag}=@hdr_dat;
print "$_\t$header{$_}\n" for @bmp_tag;

#------------------------------------------#

# get the RGB info and write into txt file #

#------------------------------------------#

my @table_R;
my @table_G;
my @table_B;

if ( $data_format eq 'H' ) {
        &process_H_format ;
}
else {
        &process_C_format ;
}

open INFOTXT, "> $filename.txt"
        or die "Can't open $filename.txt: $!";

print INFOTXT "R\n";
print INFOTXT "@table_R\n";
print INFOTXT "G\n";
print INFOTXT "@table_G\n";
print INFOTXT "B\n";
print INFOTXT "@table_B\n";


#------------------------------------------#

# convert RGB to YCbCr #

#------------------------------------------#

my ( @YR_LUT, @CbR_LUT, @CrR_LUT );
my ( @YG_LUT, @CbG_LUT, @CrG_LUT );
my ( @YB_LUT, @CbB_LUT, @CrB_LUT );
# call subroutine

&prepare_Y_LUT ;
&prepare_Cb_LUT ;
&prepare_Cr_LUT ;

# get the YCbCr data according to LUT

my ( @table_Y, @table_Cb, @table_Cr );
for ( 0..$#table_R ) {


        my $R = ( $data_format eq "H" ) ? hex( $table_R[$_] ) : $table_R[$_];
        my $G = ( $data_format eq "H" ) ? hex( $table_G[$_] ) : $table_G[$_];
        my $B = ( $data_format eq "H" ) ? hex( $table_B[$_] ) : $table_B[$_];
        
        push @table_Y, int( ($YR_LUT[$R]+$YG_LUT[$G]+$YB_LUT[$B]) / 2**16 );
        push @table_Cb, ( int(($CbR_LUT[$R]+$CbG_LUT[$G]+$CbB_LUT[$B]) / 2**16) + 128 );
        push @table_Cr, ( int(($CrR_LUT[$R]+$CrG_LUT[$G]+$CrB_LUT[$B]) / 2**16) + 128 );
}

# write into file

print INFOTXT "Y\n";
print INFOTXT "@table_Y\n";
print INFOTXT "Cb\n";
print INFOTXT "@table_Cb\n";
print INFOTXT "Cr\n";
print INFOTXT "@table_Cr\n";

close INFOTXT;

############################################################################

#-----------------------------------------#

# subrountine definition #

#-----------------------------------------#

sub process_H_format {
        my $data = join '', @rgb_data;
        
        # reorder the image data

        my $offset = $header{ 'biWidth' } * 3 * 2;
        my @lines = reverse ($data =~ /([\w\d]{$offset})/ig );
        #print "@lines\n";

        my $reorder_data = join '', @lines;

        #

        while ( $reorder_data =~ /([\w\d]{2})([\w\d]{2})([\w\d]{2})/ig ) {
                push @table_R, $3;
                push @table_G, $2;
                push @table_B, $1;
                #print "R=>$3 : G=>$2 : B=>$1\n";

        }
}

sub process_C_format {
        # reorder the image data

        my @reorder_data;
    
        for( my $y=0; $y < $header{ 'biHeight' }; $y++ ) {
                my @lines;
                my $x_count = $header{ 'biWidth' } * 3;
                while( $x_count-- ) {
                        push @lines, pop @rgb_data;
                }
                #print "@lines\n";

                unshift @reorder_data, @lines;
        }
        #print "@reorder_data\n";


        my $size = $header{ 'biWidth' } * $header{ 'biHeight' };
        while ( $size-- ) {
                #print $size, "\n";

                push @table_B, pop @reorder_data;
                push @table_G, pop @reorder_data;
                push @table_R, pop @reorder_data;
        }
}

# prepare the YCbCr data

sub prepare_Y_LUT {
        for ( 0..255 ) {
                $YR_LUT[$_] = int(65536*0.299+0.5) * $_;
                $YG_LUT[$_] = int(65536*0.587+0.5) * $_;
                $YB_LUT[$_] = int(65536*0.114+0.5) * $_;
        }
}

sub prepare_Cb_LUT {
        for ( 0..255 ) {
                $CbR_LUT[$_] = int(65536*-0.16874+0.5) * $_;
                $CbG_LUT[$_] = int(65536*-0.33126+0.5) * $_;
                $CbB_LUT[$_] = 32768 * $_;
        }
}

sub prepare_Cr_LUT {
        for ( 0..255 ) {
                $CrR_LUT[$_] = 32768 * $_;
                $CrG_LUT[$_] = int(65536*-0.41869+0.5) * $_;
                $CrB_LUT[$_] = int(65536*-0.08131+0.5) * $_;
        }
}

阅读(1409) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~