鮮鋭化フィルタ

sharping

入力画像に対して平滑化処理を施し、その結果を元の画像から引くことにより、元の画像のエッジ部分が取り出されたような画像が得られる。このような処理を鮮鋭化(sharping)処理と呼ばれています。

以下に加重平滑化した後に鮮鋭化した画像を載せておきます。

この鮮鋭化では、中心のサンマの部分にだけ鮮鋭化を掛けてあり、周辺は加重平滑化のフィルタ効果を残しています。

sanma_original
原画
sanma_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  }

親プログラムについての解説は、フィルタ効果領域のサブルーチンが増えているものの基本的には前ページの平滑化フィルタと同じですので省略します。




TITLE

自己紹介

50才になる半導体エンジニアです。
大学で電子電気工学を学び、1990年にその分野のまま就職。ASICやマイコンの設計を長く続けてきましたが20年も同じ分野にいると業態も衰退したり変化するもので退職し、今は外資のIT系会社に再就職して設計請負業をやっております。
お問い合わせは
nakata.xianzhi@outlook.com







Linux と 小ネタ

デジタル回路設計

海外駐在後記