読者です 読者をやめる 読者になる 読者になる

画像の色情報を平均化し、単色にする方法

画像を、単純化して置き換えるような処理をしたかった。
そのために、画像内の色情報を複数プロットし、平均化する処理を書いてみた。

こんな風にできたよ。

こんな画像を読み込ませると、

処理して、

こんな色にしてくれる。

Image::Magick使って、色情報取得

package Package;

use strict;
use Image::Magick;

sub new {
    my ($pkg, $param) = @_;
    my $hash = {
        img  => $param->{'img'},
        plot => (defined $param->{'plot'} and $param->{'plot'} > 0) ? $param->{'plot'} : 3,
        };
    return bless $hash, $pkg;
}

sub get_average_color {
    my ($self) = shift;
    
    my $image = Image::Magick->new;
    $image->Read($self->{'img'});
    my($width, $height)= $image->Get('width', 'height');

    if ($width < $self->{'plot'} or $height < $self->{'plot'}) {
        return 0;
    }
    my $return_info = {};
    my ($one_plot_x,$one_plot_y) = ($width / $self->{'plot'}, $height / $self->{'plot'});
    my ($x, $y) = (int ($one_plot_x / 2), int ($one_plot_y / 2));
    my $color_info = {
        r => 0,
        g => 0,
        b => 0,
        count => 0,
    };
    for (my $i = 0; $i < $self->{'plot'}; $i++) {
        for (my $j = 0; $j < $self->{'plot'}; $j++) {
            my ($r, $g, $b, $ugh) = split ',', $image->Get("pixel[" . $x . "," . $y . "]");
            
            #画像の一部が透明処理されていた場合、背景色が白という前提で補正。
            #背景色が白じゃない場合、もう、そんなことわからん・・。
            $r += $ugh if $ugh != 0;
            $r = 65535 if $r > 65535;
            $g += $ugh if $ugh != 0;
            $g = 65535 if $g > 65535;
            $b += $ugh if $ugh != 0;
            $b = 65535 if $b > 65535;

            #RGBそれぞれで色を足していく
            $color_info->{'r'} += $r;
            $color_info->{'g'} += $g;
            $color_info->{'b'} += $b;
            $color_info->{'count'}++;
            $x += $one_plot_x;
        }
        $x = int ($one_plot_x / 2);
        $y += $one_plot_y;
    }

    #プロットした数で割り、平均を出す
    $color_info->{'r'} = int($color_info->{'r'} / $color_info->{'count'});
    $return_info->{'r'} = $color_info->{'r'};
    $color_info->{'g'} = int($color_info->{'g'} / $color_info->{'count'});
    $return_info->{'g'} = $color_info->{'g'};
    $color_info->{'b'} = int($color_info->{'b'} / $color_info->{'count'});
    $return_info->{'b'} = $color_info->{'b'};

    #16進数化
    $color_info->{'r'} = int($color_info->{'r'} / 256);
    $color_info->{'g'} = int($color_info->{'g'} / 256);
    $color_info->{'b'} = int($color_info->{'b'} / 256);

    $color_info->{'r'} = unpack("H2", pack("C", $color_info->{'r'}));
    $color_info->{'g'} = unpack("H2", pack("C", $color_info->{'g'}));
    $color_info->{'b'} = unpack("H2", pack("C", $color_info->{'b'}));
    
    #16以下だった場合、先頭に0を付加
    $color_info->{'r'} = "0".$color_info->{'r'} if ($color_info->{'r'} =~ /^[0-9a-fA-F]{1}$/);
    $color_info->{'g'} = "0".$color_info->{'g'} if ($color_info->{'g'} =~ /^[0-9a-fA-F]{1}$/);
    $color_info->{'b'} = "0".$color_info->{'b'} if ($color_info->{'b'} =~ /^[0-9a-fA-F]{1}$/);
    

    $return_info->{'color'} = $color_info->{'r'} . $color_info->{'g'} . $color_info->{'b'};
    return $return_info;
}


結果

$VAR1 = {
          'color' => 'b6d6d8',
          'r' => 46680,
          'b' => 55465,
          'g' => 55019
        };


ここ数日やってたやりたいことが、ほぼほぼ完成したよ。

公開環境できたら、公開します。