The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl
# -*- mode: perl; coding: utf-8; tab-width: 4; -*-

use strict;
use warnings;
use lib qw(blib/lib blib/arch);
use Cv;
use File::Basename;
use List::Util qw(max min);

# Load the source image. HighGUI use.
my $file_name = @ARGV > 0 ? shift : dirname($0).'/'."baboon.jpg";
my $src_image = Cv->LoadImage($file_name, CV_LOAD_IMAGE_GRAYSCALE) or 
    die "Image was not loaded.\n";

my $hist_size = 64;
my $ranges = [ [0, 256] ];
my $hist = Cv::Histogram->new([$hist_size], CV_HIST_ARRAY, $ranges);
my $lut = Cv::Mat->new([1, 256], CV_8UC1);

my $brightness = 100;
my $contrast = 100;
Cv->NamedWindow("image");
Cv->CreateTrackbar("brightness", "image", $brightness, 200, \&update_brightcont);
Cv->CreateTrackbar("contrast", "image", $contrast, 200, \&update_brightcont);
Cv->NamedWindow("histogram");

&update_brightcont;
Cv->WaitKey;

# brightness/contrast callback function
sub update_brightcont {
	my $brightness = $brightness - 100;
	my $contrast = $contrast - 100;

	# The algorithm is by Werner D. Streidt
	# (http://visca.com/ffactory/archives/5-99/msg00021.html)
	my ($a, $b);
	if ($contrast > 0) {
		my $delta = 127 * $contrast / 100;
		$a = 255 / (255 - $delta*2);
		$b = $a * ($brightness - $delta);
	} else {
		my $delta = -128 * $contrast / 100;
		$a = (256 - $delta*2) / 255.;
		$b = $a * $brightness + $delta;
	}
	$lut->set([0, $_], [ min(max(0, cvRound($a * $_ + $b)), 255) ])
		for (0 .. 255);
	my $dst_image = $src_image->LUT($lut);
	$dst_image->ShowImage("image");

	my $hist_image = Cv::Image->new([200, 320], CV_8UC1);
	$hist->CalcHist([$dst_image]);
	$dst_image->Zero;
	$hist->GetMinMaxHistValue(
		my $min_val, my $max_val, my $min_idx, my $max_idx,
		);
	if ($max_val) {
		my $bins = $hist->bins;
		$bins->ConvertScale($bins, $hist_image->height / $max_val, 0);
	}
	# $hist->NormalizeHist(1000);
	my ($black, $white) = (cvScalarAll(0), cvScalarAll(255));
	$hist_image->fill($white);
	my $bin_w = cvRound($hist_image->width / $hist_size);
	for (0 .. $hist_size - 1) {
		my ($x, $y) = ($_ * $bin_w, $hist_image->height);
		my $pt1 = [$x, $y];
		my $pt2 = [$x + $bin_w, $y - cvRound($hist->QueryHistValue($_))];
		$hist_image->Rectangle($pt1, $pt2, $black, -1, 8, 0);
	}
	$hist_image->ShowImage("histogram");
}