AI-MXNet

 view release on metacpan or  search on metacpan

lib/AI/MXNet/Image.pm  view on Meta::CPAN

    AI::MXNet::NDArray $src
    Shape              $size
    Num                $min_area
    ArrayRef[Int]      [$from, $to] # $ratio
    Maybe[Int]         $interp=2

    Returns:
    --------
    ($cropped_image, [$x0, $y0, $new_w, $new_h])
=cut

method random_size_crop(AI::MXNet::NDArray $src, Shape $size, Num $min_area, ArrayRef[Num] $ratio, Maybe[Int] $interp=2)
{
    my ($h, $w) = @{ $src->shape };
    my ($from, $to) = @{ $ratio };
    my $new_ratio = $from + ($to-$from) * rand;
    my $max_area;
    if($new_ratio * $h > $w)
    {
        $max_area = $w*int($w/$new_ratio);
    }
    else
    {
        $max_area = $h*int($h*$new_ratio);
    }

    $min_area *= $h*$w;
    if($max_area < $min_area)
    {
        return __PACKAGE__->random_crop($src, $size, $interp);
    }
    my $new_area = $min_area + ($max_area-$min_area) * rand;
    my $new_w = int(sqrt($new_area*$new_ratio));
    my $new_h = $new_w;

    assert($new_w <= $w and $new_h <= $h);
    my $x0 = int(rand($w - $new_w + 1));
    my $y0 = int(rand($h - $new_h + 1));

    my $out = __PACKAGE__->fixed_crop($src, $x0, $y0, $new_w, $new_h, $size, $interp);
    return ($out, [$x0, $y0, $new_w, $new_h]);
}

=head2 ResizeAug

    Makes "resize shorter edge to size augumenter" closure.

    Parameters:
    -----------
    Shape              $size
    Int                $interp=2

    Returns:
    --------
    CodeRef that accepts AI::MXNet::NDArray $src as input
    and returns [__PACKAGE__->resize_short($src, $size, $interp)]
=cut

method ResizeAug(Shape $size, Int $interp=2)
{
    my $aug = sub {
        my $src = shift;
        return [__PACKAGE__->resize_short($src, $size, $interp)];
    };
    return $aug;
}

=head2 RandomCropAug

    Makes "random crop augumenter" closure.

    Parameters:
    -----------
    Shape              $size
    Int                $interp=2

    Returns:
    --------
    CodeRef that accepts AI::MXNet::NDArray $src as input
    and returns [(__PACKAGE__->random_crop($src, $size, $interp))[0]]
=cut

method RandomCropAug(Shape $size, Int $interp=2)
{
    my $aug = sub {
        my $src = shift;
        return [(__PACKAGE__->random_crop($src, $size, $interp))[0]];
    };
    return $aug;
}

=head2 RandomSizedCropAug

    Makes "random crop augumenter" closure.

    Parameters:
    -----------
    Shape              $size
    Num                $min_area
    ArrayRef[Num]      $ratio
    Int                $interp=2

    Returns:
    CodeRef that accepts AI::MXNet::NDArray $src as input
    and returns [(__PACKAGE__->random_size_crop($src, $size, $min_area, $ratio, $interp))[0]]
=cut

method RandomSizedCropAug(Shape $size, Num $min_area, ArrayRef[Num] $ratio, Int $interp=2)
{
    my $aug = sub {
        my $src = shift;
        return [(__PACKAGE__->random_size_crop($src, $size, $min_area, $ratio, $interp))[0]];
    };
    return $aug;
}

=head2 CenterCropAug

    Makes "center crop augumenter" closure.

    Parameters:
    -----------
    Shape              $size
    Int                $interp=2

    Returns:
    CodeRef that accepts AI::MXNet::NDArray $src as input
    and returns [(__PACKAGE__->center_crop($src, $size, $interp))[0]]
=cut

method CenterCropAug(Shape $size, Int $interp=2)
{
    my $aug = sub {
        my $src = shift;
        return [(__PACKAGE__->center_crop($src, $size, $interp))[0]];
    };
    return $aug;
}

=head2 RandomOrderAug

    Makes "Apply list of augmenters in random order" closure.

    Parameters:
    -----------
    ArrayRef[CodeRef]  $ts

    Returns:
    --------
    CodeRef that accepts AI::MXNet::NDArray $src as input
    and returns ArrayRef[AI::MXNet::NDArray]
=cut

method RandomOrderAug(ArrayRef[CodeRef] $ts)
{
    my $aug = sub {
        my $src = shift;
        my @ts = List::Util::shuffle(@{ $ts });
        my @tmp;
        for my $t (@ts)
        {
            push @tmp, &{$t}($src);
        }
        return \@tmp;
    };
    return $aug;
}

=head2 RandomOrderAug

    Makes "Apply random brightness, contrast and saturation jitter in random order" closure

    Parameters:
    -----------
    Num $brightness
    Num $contrast
    Num $saturation

    Returns:
    --------
    CodeRef that accepts AI::MXNet::NDArray $src as input
    and returns ArrayRef[AI::MXNet::NDArray]
=cut

method ColorJitterAug(Num $brightness, Num $contrast, Num $saturation)
{
    my @ts;
    my $coef = AI::MXNet::NDArray->array([[[0.299, 0.587, 0.114]]]);
    if($brightness > 0)
    {
        my $baug = sub { my $src = shift;
            my $alpha = 1 + -$brightness + 2 * $brightness * rand;
            $src *= $alpha;
            return [$src];
        };
        push @ts, $baug;
    }

    if($contrast > 0)
    {
        my $caug = sub { my $src = shift;
            my $alpha = 1 + -$contrast + 2 * $contrast * rand;
            my $gray  = $src*$coef;
            $gray = (3.0*(1.0-$alpha)/$gray->size)*$gray->sum;
            $src *= $alpha;
            $src += $gray;
            return [$src];
        };
        push @ts, $caug;
    }

    if($saturation > 0)
    {
        my $saug = sub { my $src = shift;
            my $alpha = 1 + -$saturation + 2 * $saturation * rand;
            my $gray  = $src*$coef;
            $gray = AI::MXNet::NDArray->sum($gray, { axis=>2, keepdims =>1 });
            $gray *= (1.0-$alpha);
            $src *= $alpha;
            $src += $gray;
            return [$src];
        };
        push @ts, $saug;
    }

    return __PACKAGE__->RandomOrderAug(\@ts);
}

=head2 LightingAug

    Makes "Add PCA based noise" closure.

    Parameters:
    -----------
    Num $alphastd
    PDL $eigval
    PDL $eigvec

    Returns:
    --------
    CodeRef that accepts AI::MXNet::NDArray $src as input
    and returns ArrayRef[AI::MXNet::NDArray]
=cut

method LightingAug(Num $alphastd, PDL $eigval, PDL $eigvec)
{
    my $aug = sub { my $src = shift;
        my $alpha = AI::MXNet::NDArray->zeros([3]);
        AI::MXNet::Random->normal(0, $alphastd, { out => $alpha });
        my $rgb = ($eigvec*$alpha->aspdl) x $eigval;
        $src += AI::MXNet::NDArray->array($rgb);
        return [$src]
    };
    return $aug
}

=head2 ColorNormalizeAug

    Makes "Mean and std normalization" closure.

    Parameters:
    -----------
    PDL $mean
    PDL $std

    Returns:
    --------
    CodeRef that accepts AI::MXNet::NDArray $src as input
    and returns [__PACKAGE__->color_normalize($src, $mean, $std)]
=cut

method ColorNormalizeAug(PDL $mean, PDL $std)
{
    $mean = AI::MXNet::NDArray->array($mean);
    $std = AI::MXNet::NDArray->array($std);
    my $aug = sub { my $src = shift;
        return [__PACKAGE__->color_normalize($src, $mean, $std)]
    };
    return $aug;
}

=head2 HorizontalFlipAug

    Makes "Random horizontal flipping" closure.

    Parameters:
    -----------
    Num $p < 1

    Returns:
    --------
    CodeRef that accepts AI::MXNet::NDArray $src as input
    and returns [$p > rand ? AI::MXNet::NDArray->flip($src, axis=1>) : $src]
=cut

method HorizontalFlipAug(Num $p)
{
    my $aug = sub { my $src = shift;
        return [$p > rand() ? AI::MXNet::NDArray->flip($src, { axis=>1 }) : $src]
    };
    return $aug;
}

=head2 CastAug

    Makes "Cast to float32" closure.

    Returns:
    --------
    CodeRef that accepts AI::MXNet::NDArray $src as input
    and returns [$src->astype('float32')]
=cut

method CastAug()
{
    my $aug = sub { my $src = shift;
        return [$src->astype('float32')]
    };
    return $aug;
}

=head2 CreateAugmenter

    Create augumenter list

    Parameters:
    -----------
    Shape          :$data_shape,
    Bool           :$resize=0,
    Bool           :$rand_crop=0,
    Bool           :$rand_resize=0,
    Bool           :$rand_mirror=0,
    Maybe[Num|PDL] :$mean=,
    Maybe[Num|PDL] :$std=,
    Num            :$brightness=0,
    Num            :$contrast=0,
    Num            :$saturation=0,
    Num            :$pca_noise=0,
    Int            :$inter_method=2
=cut

method CreateAugmenter(
Shape          :$data_shape,
Bool           :$resize=0,
Bool           :$rand_crop=0,
Bool           :$rand_resize=0,
Bool           :$rand_mirror=0,
Maybe[Num|PDL] :$mean=,
Maybe[Num|PDL] :$std=,
Num            :$brightness=0,
Num            :$contrast=0,
Num            :$saturation=0,
Num            :$pca_noise=0,
Int            :$inter_method=2
)
{
    my @auglist;
    if($resize > 0)
    {
        push @auglist, __PACKAGE__->ResizeAug($resize, $inter_method);
    }

    my $crop_size = [$data_shape->[2], $data_shape->[1]];
    if($rand_resize)
    {
        assert($rand_crop);
        push @auglist, __PACKAGE__->RandomSizedCropAug($crop_size, 0.3, [3.0/4.0, 4.0/3.0], $inter_method);
    }
    elsif($rand_crop)
    {
        push @auglist, __PACKAGE__->RandomCropAug($crop_size, $inter_method);
    }
    else
    {
        push @auglist, __PACKAGE__->CenterCropAug($crop_size, $inter_method);
    }

lib/AI/MXNet/Image.pm  view on Meta::CPAN


    Parameters
    ----------
    batch_size : Int
        Number of examples per batch
    data_shape : Shape
        Data shape in (channels, height, width).
        For now, only RGB image with 3 channels is supported.
    label_width : Int
        dimension of label
    path_imgrec : str
        path to image record file (.rec).
        Created with tools/im2rec.py or bin/im2rec
    path_imglist : str
        path to image list (.lst)
        Created with tools/im2rec.py or with custom script.
        Format: index\t[one or more label separated by \t]\trelative_path_from_root
    imglist: array ref
        a list of image with the label(s)
        each item is a list [imagelabel: float or array ref of float, imgpath]
    path_root : str
        Root folder of image files
    path_imgidx : str
        Path to image index file. Needed for partition and shuffling when using .rec source.
    shuffle : bool
        Whether to shuffle all images at the start of each iteration.
    Can be slow for HDD.
    part_index : int
        Partition index
    num_parts : int
        Total number of partitions.
    data_name='data' Str
    label_name='softmax_label' Str
    kwargs : hash ref with any additional arguments for augmenters
=cut

has 'batch_size'  => (is => 'ro', isa => 'Int',   required => 1);
has 'data_shape'  => (is => 'ro', isa => 'Shape', required => 1);
has 'label_width' => (is => 'ro', isa => 'Int',   default  => 1);
has 'data_name'   => (is => 'ro', isa => 'Str',   default  => 'data');
has 'label_name'  => (is => 'ro', isa => 'Str',   default  => 'softmax_label');
has [qw/path_imgrec
        path_imglist
        path_root
        path_imgidx
    /]            => (is => 'ro', isa => 'Str');
has 'shuffle'     => (is => 'ro', isa => 'Bool', default => 0);
has 'part_index'  => (is => 'ro', isa => 'Int', default => 0);
has 'num_parts'   => (is => 'ro', isa => 'Int', default => 0);
has 'aug_list'    => (is => 'rw', isa => 'ArrayRef[CodeRef]');
has 'imglist'     => (is => 'rw', isa => 'ArrayRef|HashRef');
has 'kwargs'      => (is => 'ro', isa => 'HashRef');
has [qw/imgidx
        imgrec
        seq
        cur
        provide_data
        provide_label
           /]     => (is => 'rw', init_arg => undef);

sub BUILD
{
    my $self = shift;
    assert($self->path_imgrec or $self->path_imglist or ref $self->imglist eq 'ARRAY');
    if($self->path_imgrec)
    {
        print("loading recordio...\n");
        if($self->path_imgidx)
        {
            $self->imgrec(
                AI::MXNet::IndexedRecordIO->new(
                    idx_path => $self->path_imgidx,
                    uri => $self->path_imgrec,
                    flag => 'r'
                )
            );
            $self->imgidx([@{ $self->imgrec->keys }]);
        }
        else
        {
            $self->imgrec(AI::MXNet::RecordIO->new(uri => $self->path_imgrec, flag => 'r'));
        }
    }
    my %imglist;
    my @imgkeys;
    if($self->path_imglist)
    {
        print("loading image list...\n");
        open(my $f, $self->path_imglist) or confess("can't open ${\ $self->path_imglist } : $!");
        while(my $line = <$f>)
        {
            chomp($line);
            my @line = split(/\t/, $line);
            my $label = AI::MXNet::NDArray->array([@line[1..@line-2]]);
            my $key   = $line[0];
            $imglist{$key} = [$label, $line[-1]];
            push @imgkeys, $key;
        }
        $self->imglist(\%imglist);
    }
    elsif(ref $self->imglist eq 'ARRAY')
    {
        print("loading image list...\n");
        my %result;
        my $index = 1;
        for my $img (@{ $self->imglist })
        {
            my $key = $index++;
            my $label;
            if(not ref $img->[0])
            {
                $label = AI::MXNet::NDArray->array([$img->[0]]);
            }
            else
            {
                $label = AI::MXNet::NDArray->array($img->[0]);
                $result{$key} = [$label, $img->[1]];
                push @imgkeys, $key;
            }
        }
        $self->imglist(\%result);



( run in 0.531 second using v1.01-cache-2.11-cpan-39bf76dae61 )