edge_detector.pl 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. #!/usr/bin/perl
  2. # Author: Daniel "Trizen" Șuteu
  3. # License: GPLv3
  4. # Date: 05 November 2015
  5. # Edit: 19 May 2016
  6. # Website: https://github.com/trizen
  7. # A very basic edge detector, which highlights the edges in an image.
  8. use 5.010;
  9. use strict;
  10. use warnings;
  11. use GD;
  12. GD::Image->trueColor(1);
  13. use List::Util qw(sum);
  14. use Getopt::Long qw(GetOptions);
  15. my $tolerance = 15; # lower tolerance => more noise
  16. GetOptions('t|tolerance=f' => \$tolerance,
  17. 'h|help' => sub { help(0) })
  18. or die "Error in command-line arguments!";
  19. sub help {
  20. my ($exit_code) = @_;
  21. print <<"EOT";
  22. usage: $0 [options] [input image] [output image]
  23. options:
  24. -t --tolerance=[0-100] : tolerance value for edges (default: $tolerance)
  25. lower values will generate more noise
  26. example:
  27. perl $0 -t=5 input.png output.png
  28. EOT
  29. exit($exit_code // 0);
  30. }
  31. my $in_file = shift(@ARGV) // help(2);
  32. my $out_file = shift(@ARGV) // 'output.png';
  33. my $img = GD::Image->new($in_file);
  34. my @matrix = ([]);
  35. my ($width, $height) = $img->getBounds;
  36. sub get_avg_pixel {
  37. sum($img->rgb($img->getPixel(@_))) / 3;
  38. }
  39. # Detect edge
  40. foreach my $y (1 .. $height - 2) {
  41. foreach my $x (1 .. $width - 2) {
  42. if ( abs(get_avg_pixel($x-1, $y ) - get_avg_pixel($x+1, $y )) / 255 * 100 > $tolerance # left <-> right
  43. or abs(get_avg_pixel($x, $y-1) - get_avg_pixel($x, $y+1)) / 255 * 100 > $tolerance # up <-> down
  44. or abs(get_avg_pixel($x-1, $y-1) - get_avg_pixel($x+1, $y+1)) / 255 * 100 > $tolerance # up-left <-> down-right
  45. or abs(get_avg_pixel($x+1, $y-1) - get_avg_pixel($x-1, $y+1)) / 255 * 100 > $tolerance # up-right <-> down-left
  46. ) {
  47. $matrix[$y][$x] = 1;
  48. }
  49. }
  50. }
  51. # Remove noise
  52. foreach my $y (1 .. $height - 2) {
  53. foreach my $x (1 .. $width - 2) {
  54. if (defined($matrix[$y][$x])) {
  55. if (!defined($matrix[$y ][$x+1])
  56. and !defined($matrix[$y ][$x-1])
  57. and !defined($matrix[$y-1][$x-1])
  58. and !defined($matrix[$y-1][$x ])
  59. and !defined($matrix[$y-1][$x+1])
  60. and !defined($matrix[$y+1][$x-1])
  61. and !defined($matrix[$y+1][$x ])
  62. and !defined($matrix[$y+1][$x+1])
  63. ) {
  64. undef $matrix[$y][$x];
  65. }
  66. }
  67. }
  68. }
  69. my $new_img = GD::Image->new($width, $height);
  70. my $bg_color = $new_img->colorAllocate(0, 0, 0);
  71. my $fg_color = $new_img->colorAllocate(255, 255, 255);
  72. for my $y (0 .. $height - 1) {
  73. for my $x (0 .. $width - 1) {
  74. $new_img->setPixel($x, $y, defined($matrix[$y][$x]) ? $fg_color : $bg_color);
  75. }
  76. }
  77. open(my $fh, '>:raw', $out_file) or die "Can't open `$out_file' for write: $!";
  78. print $fh (
  79. $out_file =~ /\.png\z/i ? $new_img->png
  80. : $out_file =~ /\.gif\z/i ? $new_img->gif
  81. : $new_img->jpeg
  82. );
  83. close $fh;