简体   繁体   中英

Using Image::Magick to split an image into smaller chunks and get relative position of each chunk

I need to split a large (up to 16384x16384px) image into smaller chunks, usually 512x512. For doing this, I'm using the simple perl script below:

#!/usr/bin/perl
use warnings;
use strict;

my $size = '512x512';

unless ($ARGV[0]) { die "Missing filename as arg" }
unless (-e $ARGV[0]) { die "$ARGV[0] not found.\n" }
my ($newfile, undef) = split(/\./,$ARGV[0]);

system("convert $ARGV[0] -crop $size $newfile" . "_%03d.png");

Now, the thing is, I need to build an index of the smaller pieces which includes the position offset in the original image, for example in the case of a 1024x1024 source image:

image_000.png    0,0
image_001.png    512,0
image_002.png    0,512 
image_003.png    512,512

...or something similar. Basically, just to keep track of the position each particular chunk had in the original image.

Since the convert command passed to system() I was thinking of just doing a glob of the files and sorting them, as some quick experimentation shows that the smaller chunks are numbered in the order left to right, top to bottom (intuitively) and build the index based on that, but I'm thinking there must be something simpler involving perls own interface to ImageMagick


So my questions then are:

1. What is the Image::Magick equivalent of convert $ARGV[0] -crop $size $newfile" . "_%03d.png ?

2. Is it possible to build the index based on data from the $image object once I have managed to avoid a system() call?

PS:

  • The chunk size doesn't change often. Hardcoding 512 is fine, so there's no need to extract that from $size ... in fact, I don't know why i chose to have that variable at all.
  • The Original image size is always divisible by the chunk size, so there's no need to worry about leftovers.
  • To make the glob() approach tricky, the images aren't always square. Perhaps using the 3rd column of the identify command can be taken into account somehow?

I solved it the only way i know how: Screw perlmagic, and do it via command line instead. The below script works on both rectangular and square images. Index is printed to the screen.

use warnings;
use strict;

my $size = '512x512';
my $offset = 512;

unless ($ARGV[0]) { die "Missing filename as arg" }
unless (-e $ARGV[0]) { die "$ARGV[0] not found.\n" }

my ($newfile, undef) = split(/\./,$ARGV[0]);
system("convert $ARGV[0] -crop $size $newfile" . "_%03d.png");

my @files = glob($newfile . "_*");
@files = sort(@files);

my (undef, undef, $origsize) = split(/\s+/,`identify $ARGV[0]`);
my ($maxX, $maxY) = split(/x/,$origsize);

$maxX /= $offset;
$maxY /= $offset;

my $x = 0;
my $y = 0;
foreach my $file (@files)
{
        print "$file\t" . $x * $offset . "\t" . $y * $offset . "\n";
        $x++;

        if ($x >= $maxX)
        {
                $x = 0;
                $y++;
        }
}


__END__

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM