June 2018 Update
This commit is contained in:
parent
ba8067c3b7
commit
22f33d4004
5278 changed files with 84726 additions and 14379 deletions
|
|
@ -1,163 +1,63 @@
|
|||
package bitmap;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
public enum ImageProcessing {
|
||||
;
|
||||
|
||||
/**
|
||||
* Image processing functions such as histogram, grayscale,..
|
||||
* here we assume we have a YUV image. so we process only luma component Y
|
||||
* the histogram can be called on luma pixel only (values from 0 to 255)
|
||||
* greyscale is done with a constant middle value of FullRange / 2 = 127
|
||||
*/
|
||||
public class ImageProc {
|
||||
public static void main(String[] args) throws IOException {
|
||||
BufferedImage img = ImageIO.read(new File("example.png"));
|
||||
|
||||
static final private Integer MAX_VAL = 255;
|
||||
static final private Integer MIN_VAL = 0;
|
||||
static final private Integer MID_RANGE = (MAX_VAL - MIN_VAL) >> 1;
|
||||
BufferedImage bwimg = toBlackAndWhite(img);
|
||||
|
||||
private static Integer[] lumaHist(Integer[] luma,Integer length) {
|
||||
// from input length, select a number of classes (intervalles )
|
||||
// usually take sqrt(length)
|
||||
if ((length == 0 )|| (luma == null)){
|
||||
return null;
|
||||
ImageIO.write(bwimg, "png", new File("example-bw.png"));
|
||||
}
|
||||
|
||||
private static int luminance(int rgb) {
|
||||
int r = (rgb >> 16) & 0xFF;
|
||||
int g = (rgb >> 8) & 0xFF;
|
||||
int b = rgb & 0xFF;
|
||||
return (r + b + g) / 3;
|
||||
}
|
||||
|
||||
private static BufferedImage toBlackAndWhite(BufferedImage img) {
|
||||
int width = img.getWidth();
|
||||
int height = img.getHeight();
|
||||
|
||||
int[] histo = computeHistogram(img);
|
||||
|
||||
int median = getMedian(width * height, histo);
|
||||
|
||||
BufferedImage bwimg = new BufferedImage(width, height, img.getType());
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
bwimg.setRGB(x, y, luminance(img.getRGB(x, y)) >= median ? 0xFFFFFFFF : 0xFF000000);
|
||||
}
|
||||
double stepd = Math.sqrt(length);
|
||||
// define the interval width
|
||||
int step = (int)stepd ;
|
||||
Integer width = (int)(length / stepd);
|
||||
// define step Lists containing only values in one interval
|
||||
// done with a loop generating a new list that discard lower part
|
||||
// the luma buff is fist sorted to split the array correctly
|
||||
// only values greater than width are kept in a new list
|
||||
|
||||
List<Integer> interv[] = new ArrayList[step];
|
||||
Integer hist[] = new Integer[step];
|
||||
interv[0] = Arrays.stream(luma)
|
||||
.parallel()
|
||||
.sorted()
|
||||
.filter(value -> value >= width)
|
||||
.collect(Collectors.toList());
|
||||
hist[0] = length - interv[0].size();
|
||||
|
||||
// here due to a lambda expression limitation
|
||||
// we can not modify the width value. (should be a final var)
|
||||
// so we decrease each reaming values with width, and store in a new list
|
||||
// the filter is than the same across iterations
|
||||
// histogram is computed in the same loop: the number of data for the interval
|
||||
// is equal to the previous list size minus the new list size
|
||||
for (int i =1; i < step; i++){
|
||||
|
||||
interv[i] = interv[i-1].stream()
|
||||
.map(value -> value -= width)
|
||||
.filter(value -> value >= width)
|
||||
.collect(Collectors.toList());
|
||||
hist[i] = interv[i-1].size() - interv[i].size();
|
||||
}
|
||||
|
||||
return hist;
|
||||
}
|
||||
|
||||
private static Integer[] blackAndWhite(Integer[] luma,Integer length) {
|
||||
|
||||
List<Integer> bwPict ;
|
||||
// compute the average value of the stream
|
||||
// need to transform the List<Integer> in List<String> to transform in int !!!
|
||||
|
||||
double average;
|
||||
average = Stream.of(luma).map(i -> i.toString())
|
||||
.mapToInt(Integer::parseInt)
|
||||
.average()
|
||||
.getAsDouble();
|
||||
System.out.println("Average value : " +average);
|
||||
// compare each value with the average
|
||||
// if less set to 0 (black) if more, set to 255 (black)
|
||||
bwPict= Arrays.stream(luma)
|
||||
.parallel()
|
||||
.map(value -> (value > average) ?MAX_VAL: MIN_VAL)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Integer retPict[] = new Integer[bwPict.size()];
|
||||
return bwPict.toArray(retPict);
|
||||
}
|
||||
return bwimg;
|
||||
}
|
||||
|
||||
public static void main (String[] args)
|
||||
{
|
||||
Integer[] histo;
|
||||
Integer img_y[] = new Integer[256];
|
||||
// generate ramdom values just for testing algo
|
||||
Random r = new Random();
|
||||
for (int i=0;i< img_y.length; i++) {
|
||||
img_y[i] = r.nextInt(MAX_VAL);
|
||||
private static int[] computeHistogram(BufferedImage img) {
|
||||
int width = img.getWidth();
|
||||
int height = img.getHeight();
|
||||
|
||||
int[] histo = new int[256];
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
histo[luminance(img.getRGB(x, y))]++;
|
||||
}
|
||||
}
|
||||
return histo;
|
||||
}
|
||||
|
||||
// ********* compute histogram ********************
|
||||
histo = lumaHist(img_y,img_y.length);
|
||||
|
||||
System.out.println("histogram size =:" + histo.length );
|
||||
|
||||
int sum = 0;
|
||||
for (int i=0; i< histo.length;i++) {
|
||||
System.out.println("histo[" + i + "] =:" + histo[i]);
|
||||
sum +=histo[i];
|
||||
}
|
||||
// check results are ok
|
||||
// first check nb of elments in histo is 256
|
||||
if (sum != img_y.length){
|
||||
System.out.println("Error in histogram processing!\n"
|
||||
+ "Numbers of value not coherent");
|
||||
}
|
||||
Integer hist[] = new Integer[16];
|
||||
Arrays.fill(hist, 0);
|
||||
for (int i=0;i< 256; i++) {
|
||||
if (img_y[i] < 16) hist[0]++;
|
||||
else if (img_y[i] < 32) hist[1]++;
|
||||
else if (img_y[i] < 48) hist[2]++;
|
||||
else if (img_y[i] < 64) hist[3]++;
|
||||
else if (img_y[i] < 80) hist[4]++;
|
||||
else if (img_y[i] < 96) hist[5]++;
|
||||
else if (img_y[i] < 112) hist[6]++;
|
||||
else if (img_y[i] < 128) hist[7]++;
|
||||
else if (img_y[i] < 144) hist[8]++;
|
||||
else if (img_y[i] < 160) hist[9]++;
|
||||
else if (img_y[i] < 176) hist[10]++;
|
||||
else if (img_y[i] < 192) hist[11]++;
|
||||
else if (img_y[i] < 208) hist[12]++;
|
||||
else if (img_y[i] < 224) hist[13]++;
|
||||
else if (img_y[i] < 240) hist[14]++;
|
||||
else hist[15]++;
|
||||
|
||||
}
|
||||
if (hist.length != histo.length) {
|
||||
System.out.println("Error in histogram processing!\n"
|
||||
+ "histogram size is wrong ");
|
||||
return;
|
||||
}
|
||||
else {
|
||||
for (int i=0; i< histo.length;i++) {
|
||||
if (!Objects.equals(hist[i], histo[i])) {
|
||||
System.out.println("Error in histogram processing!\n"
|
||||
+ "values are different (interv= " + i
|
||||
+ " computed: " + histo[i]
|
||||
+ " theorical :" + hist[i] + "\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("Test OK\n");
|
||||
|
||||
// ********* compute grayscale image ********************
|
||||
Integer pictBW[];
|
||||
pictBW = blackAndWhite(img_y,img_y.length);
|
||||
|
||||
for (int i=0;i< img_y.length; i++) {
|
||||
System.out.println("Original[" + i +"]:" + img_y[i] +
|
||||
" BandW[" + i +"]:" +pictBW[i] );
|
||||
}
|
||||
|
||||
}
|
||||
private static int getMedian(int total, int[] histo) {
|
||||
int median = 0;
|
||||
int sum = 0;
|
||||
for (int i = 0; i < histo.length && sum + histo[i] < total / 2; i++) {
|
||||
sum += histo[i];
|
||||
median++;
|
||||
}
|
||||
return median;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,9 @@
|
|||
using Color, Images, FixedPointNumbers
|
||||
using Images, FileIO
|
||||
|
||||
ima = imread("bitmap_histogram_in.jpg")
|
||||
imb = convert(Image{Gray{Ufixed8}}, ima)
|
||||
ima = load("data/lenna50.jpg")
|
||||
imb = Gray.(ima)
|
||||
|
||||
# calculate histogram
|
||||
a = map(x->x.val.i, imb.data)
|
||||
(nothing, h) = hist(reshape(a, length(a)), -1:typemax(Uint8))
|
||||
|
||||
g = float(imb.data)
|
||||
b = g .> median(g)
|
||||
fill!(imb, Gray(0.0))
|
||||
imb[b] = Gray(1.0)
|
||||
|
||||
imwrite(imb, "bitmap_histogram_out.png")
|
||||
medcol = median(imb)
|
||||
imb[imb .≤ medcol] = Gray(0.0)
|
||||
imb[imb .> medcol] = Gray(1.0)
|
||||
save("data/lennaGray.jpg", imb)
|
||||
|
|
|
|||
61
Task/Bitmap-Histogram/Kotlin/bitmap-histogram.kotlin
Normal file
61
Task/Bitmap-Histogram/Kotlin/bitmap-histogram.kotlin
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
// version 1.2.10
|
||||
|
||||
import java.io.File
|
||||
import java.awt.image.BufferedImage
|
||||
import javax.imageio.ImageIO
|
||||
|
||||
const val BLACK = 0xff000000.toInt()
|
||||
const val WHITE = 0xffffffff.toInt()
|
||||
|
||||
fun luminance(argb: Int): Int {
|
||||
val red = (argb shr 16) and 0xFF
|
||||
val green = (argb shr 8) and 0xFF
|
||||
val blue = argb and 0xFF
|
||||
return (0.2126 * red + 0.7152 * green + 0.0722 * blue).toInt()
|
||||
}
|
||||
|
||||
val BufferedImage.histogram: IntArray
|
||||
get() {
|
||||
val lumCount = IntArray(256)
|
||||
for (x in 0 until width) {
|
||||
for (y in 0 until height) {
|
||||
var argb = getRGB(x, y)
|
||||
lumCount[luminance(argb)]++
|
||||
}
|
||||
}
|
||||
return lumCount
|
||||
}
|
||||
|
||||
fun findMedian(histogram: IntArray): Int {
|
||||
var lSum = 0
|
||||
var rSum = 0
|
||||
var left = 0
|
||||
var right = 255
|
||||
do {
|
||||
if (lSum < rSum) lSum += histogram[left++]
|
||||
else rSum += histogram[right--]
|
||||
}
|
||||
while (left != right)
|
||||
return left
|
||||
}
|
||||
|
||||
fun BufferedImage.toBlackAndWhite(median: Int) {
|
||||
for (x in 0 until width) {
|
||||
for (y in 0 until height) {
|
||||
val argb = getRGB(x, y)
|
||||
val lum = luminance(argb)
|
||||
if (lum < median)
|
||||
setRGB(x, y, BLACK)
|
||||
else
|
||||
setRGB(x, y, WHITE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val image = ImageIO.read(File("Lenna100.jpg"))
|
||||
val median = findMedian(image.histogram)
|
||||
image.toBlackAndWhite(median)
|
||||
val bwFile = File("Lenna_bw.jpg")
|
||||
ImageIO.write(image, "jpg", bwFile)
|
||||
}
|
||||
52
Task/Bitmap-Histogram/Perl-6/bitmap-histogram.pl6
Normal file
52
Task/Bitmap-Histogram/Perl-6/bitmap-histogram.pl6
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
class Pixel { has UInt ($.R, $.G, $.B) }
|
||||
class Bitmap {
|
||||
has UInt ($.width, $.height);
|
||||
has Pixel @.data;
|
||||
}
|
||||
|
||||
role PBM {
|
||||
has @.BM;
|
||||
method P4 returns Blob {
|
||||
"P4\n{self.width} {self.height}\n".encode('ascii')
|
||||
~ Blob.new: self.BM
|
||||
}
|
||||
}
|
||||
|
||||
sub getline ( $fh ) {
|
||||
my $line = '#'; # skip comments when reading image file
|
||||
$line = $fh.get while $line.substr(0,1) eq '#';
|
||||
$line;
|
||||
}
|
||||
|
||||
sub load-ppm ( $ppm ) {
|
||||
my $fh = $ppm.IO.open( :enc('ISO-8859-1') );
|
||||
my $type = $fh.&getline;
|
||||
my ($width, $height) = $fh.&getline.split: ' ';
|
||||
my $depth = $fh.&getline;
|
||||
Bitmap.new( width => $width.Int, height => $height.Int,
|
||||
data => ( $fh.slurp.ords.rotor(3).map:
|
||||
{ Pixel.new(R => $_[0], G => $_[1], B => $_[2]) } )
|
||||
)
|
||||
}
|
||||
|
||||
sub grayscale ( Bitmap $bmp ) {
|
||||
map { (.R*0.2126 + .G*0.7152 + .B*0.0722).round(1) min 255 }, $bmp.data;
|
||||
}
|
||||
|
||||
sub histogram ( Bitmap $bmp ) {
|
||||
my @gray = grayscale($bmp);
|
||||
my $threshold = @gray.sum / @gray;
|
||||
for @gray.rotor($bmp.width) {
|
||||
my @row = $_.list;
|
||||
@row.push(0) while @row % 8;
|
||||
$bmp.BM.append: @row.rotor(8).map: { :2(($_ X< $threshold)».Numeric.join) }
|
||||
}
|
||||
}
|
||||
|
||||
my $filename = './Lenna.ppm';
|
||||
|
||||
my Bitmap $b = load-ppm( $filename ) but PBM;
|
||||
|
||||
histogram($b);
|
||||
|
||||
'./Lenna-bw.pbm'.IO.open(:bin, :w).write: $b.P4;
|
||||
Loading…
Add table
Add a link
Reference in a new issue