鮮鋭化フィルタ
入力画像に対して平滑化処理を施し、その結果を元の画像から引くことにより、元の画像のエッジ部分が取り出されたような画像が得られる。このような処理を鮮鋭化(sharping)処理と呼ばれています。
以下に加重平滑化した後に鮮鋭化した画像を載せておきます。
この鮮鋭化では、中心のサンマの部分にだけ鮮鋭化を掛けてあり、周辺は加重平滑化のフィルタ効果を残しています。
原画
|
加重平滑化 -> 鮮鋭化
|
サブルーチン
以下は鮮鋭化フィルタのサブルーチンです。
ターゲットとなる画素 $org[$i][$j] とその周辺の画素を RGB に分解して ターゲットの画素を 9倍 したものから 周辺の画素値を引き算しています。そこに引数で与えられた実効値を掛け算しています。
実行値を掛け算して最大値 65535 を超える場合は 65535 に留め、周辺値を引き算することにより、 0 より小さくなる場合は 0 に留める処理をしています。
lib/sharping.pm :
1 sub sharping {
2 my $coef = $_[0];
3 my $color;
4
5 ($r[0], $g[0], $b[0]) = split /\,/, $org[$i-1][$j-1]; # up left
6 ($r[1], $g[1], $b[1]) = split /\,/, $org[$i][$j-1]; # up center
7 ($r[2], $g[2], $b[2]) = split /\,/, $org[$i+1][$j-1]; # up right
8 ($r[3], $g[3], $b[3]) = split /\,/, $org[$i-1][$j]; # center left
9 ($r[4], $g[4], $b[4]) = split /\,/, $org[$i][$j]; # center center
10 ($r[5], $g[5], $b[5]) = split /\,/, $org[$i+1][$j]; # center right
11 ($r[6], $g[6], $b[6]) = split /\,/, $org[$i-1][$j+1]; # down left
12 ($r[7], $g[7], $b[7]) = split /\,/, $org[$i][$j+1]; # down center
13 ($r[8], $g[8], $b[8]) = split /\,/, $org[$i+1][$j+1]; # down right
14 $r_sum = ( ($r[4] * 9 ) - $r[0] - $r[1] - $r[2] - $r[3] - $r[5] - $r[6] - $r[7] - $r[8] );
15 $g_sum = ( ($g[4] * 9 ) - $g[0] - $g[1] - $g[2] - $g[3] - $g[5] - $g[6] - $g[7] - $g[8] );
16 $b_sum = ( ($b[4] * 9 ) - $b[0] - $b[1] - $b[2] - $b[3] - $b[5] - $b[6] - $b[7] - $b[8] );
17 $r_sum_k = ($r_sum * $coef);
18 $g_sum_k = ($g_sum * $coef);
19 $b_sum_k = ($b_sum * $coef);
20 $r_sum_k_i = int($r_sum_k);
21 $g_sum_k_i = int($g_sum_k);
22 $b_sum_k_i = int($b_sum_k);
23 $sharp_r = ($r[4] + $r_sum_k_i);
24 $sharp_g = ($g[4] + $g_sum_k_i);
25 $sharp_b = ($b[4] + $b_sum_k_i);
26 if ($sharp_r > 65535) {
27 $sharp_r_l = 65535;
28 } elsif ($sharp_r < 0) {
29 $sharp_r_l = 0;
30 } else {
31 $sharp_r_l = $sharp_r;
30 }
26 if ($sharp_g > 65535) {
27 $sharp_g_l = 65535;
28 } elsif ($sharp_g < 0) {
29 $sharp_g_l = 0;
30 } else {
31 $sharp_g_l = $sharp_g;
32 }
23 if ($sharp_b > 65535) {
24 $sharp_b_l = 65535;
25 } elsif ($sharp_b < 0) {
26 $sharp_b_l = 0;
37 } else {
38 $sharp_b_l = $sharp_b;
39 }
40 $color = "$sharp_r_l" . ',' . "$sharp_g_l" . ',' . "$sharp_b_l";
41 return $color;
42 }
43
44 1;
フィルタ効果領域を指定するサブルーチン
画像の一部にフィルタ効果を与えることによって、画像に変化を持たせたくなり、フィルタ効果の範囲を判定するサブルーチンを作成しました。
このサブルーチンの戻り値は、フィルタ処理しているターゲット画素の座標が処理エリア内なら 1 エリア外なら 0 としています。
オプションは、フィルタ範囲の形状 ( □ または ◯ ) 、範囲の中心座標、範囲の広さ (中心からの縦,横の距離) 、横方向の比率 (長方形 または 楕円 の変化を与える) 、指定範囲の外側または内側のどちらにフィルタを与えるか、最後はターゲット画素の座標 となっています。
フィルタ形状を ◯ に指定された場合の範囲の計算には 2点間の距離を求める方程式 √( x2+y2 ) を使って求めています。
lib/apply_area.pm :
1 sub apply_area {
2 my ($shape, $center_x, $center_y, $volume, $x_ratio, $eio, $posi_x, $posi_y) = @_;
3
4 if ($shape eq "s") {
5 $x_min = $center_x - ($volume * $x_ratio);
6 $x_max = $center_x + ($volume * $x_ratio);
7 $y_min = $center_y - $volume;
8 $y_max = $center_y + $volume;
9 if ($eio eq "i") {
10 if (($posi_x >= $x_min) && ($posi_x <= $x_max) && ($posi_y >= $y_min) && ($posi_y <= $y_max)) {
11 $apply = 1;
12 } else {
13 $apply = 0;
14 }
15 } else {
16 if (($posi_x >= $x_min) && ($posi_x <= $x_max) && ($posi_y >= $y_min) && ($posi_y <= $y_max)) {
17 $apply = 0;
18 } else {
19 $apply = 1;
20 }
21 }
22 }
23
24 if ($shape eq "c") {
25 $dx = (($posi_x - $center_x) * $x_ratio);
26 $pdx = ($dx * $dx);
27 $dy = ($posi_y - $center_y);
28 $pdy = ($dy * $dy);
29 $distance = sqrt(($pdx+$pdy));
30 if ($eio eq "i") {
31 if ($distance < $volume) {
32 $apply = 1;
33 } else {
34 $apply = 0;
35 }
36 } else {
37 if ($distance < $volume) {
38 $apply = 0;
39 } else {
40 $apply = 1;
41 }
42 }
43 }
44 return $apply;
45 }
46
47 1;
親プログラム
上の鮮鋭化フィルタのサブルーチンとフィルタ効果領域を判定するサブルーチンを使って、実際の画像処理をするのが以下のプログラムです。
sharping.pl :
1 #!/usr/bin/perl
2
3 use Getopt::Long;
4
5 use lib '/home/user/Lab/ImageProcessing/Perl/lib';
6 require read_jpg;
7 require sharping;
8 require apply_area;
9
10 sub print_synopsis {
11 print "Options : \n";
12 print " --input_file : \n";
13 print " input original file name.\n";
14 print " --coef : \n";
15 print " coefficient value of shaping.\n";
16 print " if not defined, 0.0001 is set to this option.\n";
17 print " --shape : \n";
18 print " shape of filer area either s as square or c as circle.\n";
19 print " if not defined, n is set to this option.\n";
20 print " --center : \n";
21 print " center position x,y\n";
22 print " if not defined, 960,540 is set to this option.\n";
23 print " --volume : \n";
24 print " filter area size. distance from center.\n";
25 print " if not defined, 1400 is set to this option.\n";
26 print " --xratio : \n";
27 print " ratio of x size of filter area\n";
28 print " if not defined, 1 is set to this option.\n";
29 print " --eio : \n";
30 print " filter effective area either i as inside or o as outside.\n";
31 print " if not defined, o is set to this option.\n";
32 }
33
34 &GetOptions(
35 'input_file=s' => \$in_file,
36 'coef=f' => \$coef,
37 'shape=s' => \$in_shape,
38 'center=s' => \$in_center,
39 'volume=i' => \$in_volume,
40 'xratio=f' => \$in_xratio,
41 'eio=s' => \$in_eio,
42 'nodisp' => \$in_nodisp,
43 );
44
45 if (!defined($in_file)) {
46 print "##ERROR## input file has not been defined\n";
47 &print_synopsis;
48 exit;
49 }
50
51 if (!defined($coef)) {
52 print "##WARNING## coefficient has not been defined. 0.001 is used as temporary.\n";
53 $coef = 0.001;
54 }
55
56 if (!defined($in_shape)) {
57 print "shape of averaging area is not defined\n";
58 $shape = 'n';
59 } else {
60 if (!(($in_shape eq "s")||($in_shape eq "c"))) {
61 print "##ERROR## invalid shape is defined. define s as square or c as circle\n";
62 exit;
63 } else {
64 $shape = $in_shape;
65 }
66 }
67
68 if (!defined($in_center)) {
69 $center_x = 960;
70 $center_y = 540;
71 } else {
72 @tmp_center = split /\,/, $in_center;
73 $center_x = $tmp_center[0];
74 $center_y = $tmp_center[1];
75 }
76
77 if (!defined($in_volume)) {
78 $volume = 1400;
79 } else {
80 $volume = $in_volume;
81 }
82
83 if (!defined($in_xratio)) {
84 $xratio = 1;
85 } else {
86 $xratio = $in_xratio;
87 }
88
89 if (!defined($in_eio)) {
90 $eio = 'o';
91 } else {
92 if (!(($in_eio eq "i")||($in_eio eq "o"))) {
93 print "##ERROR## invalid effective area is defined. define i as inside or o as outside\n";
94 exit;
95 } else {
96 $eio = $in_eio;
97 }
98 }
99
100 &read_jpg($in_file);
101
102 print "sharping\n";
103 for ($j = 0; $j < $size_y; $j++) {
104 for ($i = 0; $i < $size_x; $i++) {
105 if (($i < 1) || ($i > ($size_x - 1)) || ($j < 1) || ($j > ($size_y - 1))) {
106 $sharp[$i][$j] = $org[$i][$j];
107 } else {
108 if ($shape eq "n") {
109 $sharp[$i][$j] = &sharping($coef);
110 } else {
111 $apply_calc = &apply_area($shape, $center_x, $center_y, $volume, $xratio, $eio, $i, $j);
112 if ($apply_calc == 1) {
113 $sharp[$i][$j] = &sharping($coef);
114 } else {
115 $sharp[$i][$j] = $org[$i][$j];
116 }
117 }
118 }
119 }
120 }
121
122 print "output text file\n";
123 open(OUT_TEXT, ">", "../Temp/sharping.txt") or die "##ERROR## Could not open output file : ../Temp/sharping.txt";
124 print OUT_TEXT "$header\n";
125 for ($y = 0; $y < $size_y; $y++) {
126 for ($x = 0; $x < $size_x; $x++) {
127 $state = "$x" . ',' . "$y" . ': ' . '(' . "$sharp[$x][$y]" . ')';
128 print OUT_TEXT "$state\n";
129 }
130 }
131 close OUT_TEXT;
132
133 print "convert text to jpeg\n";
134 `convert ../Temp/sharping.txt ../Temp/sharping.jpg`;
135
136 if (!defined($in_nodisp)) {
137 if ( ($size_x <= 1920) && ($size_y <= 1080) ) {
138 print "display\n";
139 `display ../Temp/sharping.jpg`;
140 } else {
141 print "jpeg size is too large, open with gimp\n";
142 }
143 }
親プログラムについての解説は、フィルタ効果領域のサブルーチンが増えているものの基本的には前ページの平滑化フィルタと同じですので省略します。
|
自己紹介
50才になる半導体エンジニアです。
大学で電子電気工学を学び、1990年にその分野のまま就職。ASICやマイコンの設計を長く続けてきましたが20年も同じ分野にいると業態も衰退したり変化するもので退職し、今は外資のIT系会社に再就職して設計請負業をやっております。
お問い合わせは
nakata.xianzhi@outlook.com
Linux と 小ネタ
デジタル回路設計
海外駐在後記
|