Bitmap/Histogram: Difference between revisions
Content added Content deleted
m (1-bit gray and save as PBM) |
(→{{header|Java}}: Replace horribly complicated code with a clean and nice solution) |
||
Line 658: | Line 658: | ||
=={{header|Java}}== |
=={{header|Java}}== |
||
<lang Java>import java.awt.image.BufferedImage; |
|||
This solution is based on JAVA 8 stream API |
|||
import java.io.File; |
|||
<lang Java> |
|||
import java.io.IOException; |
|||
package bitmap; |
|||
import javax.imageio.ImageIO; |
|||
public enum ImageProcessing { |
|||
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 static void main(String[] args) throws IOException { |
|||
/** |
|||
BufferedImage img = ImageIO.read(new File("example.png")); |
|||
* 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 { |
|||
BufferedImage bwimg = toBlackAndWhite(img); |
|||
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; |
|||
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; |
|||
} |
|||
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 |
|||
ImageIO.write(bwimg, "png", new File("example-bw.png")); |
|||
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++){ |
|||
private static int luminance(int rgb) { |
|||
interv[i] = interv[i-1].stream() |
|||
int r = (rgb >> 16) & 0xFF; |
|||
int g = (rgb >> 8) & 0xFF; |
|||
int b = rgb & 0xFF; |
|||
.collect(Collectors.toList()); |
|||
return (r + b + g) / 3; |
|||
} |
|||
return hist; |
|||
} |
|||
private static BufferedImage toBlackAndWhite(BufferedImage img) { |
|||
int width = img.getWidth(); |
|||
int height = img.getHeight(); |
|||
// 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); |
|||
} |
|||
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); |
|||
} |
|||
int[] histo = computeHistogram(img); |
|||
// ********* compute histogram ******************** |
|||
histo = lumaHist(img_y,img_y.length); |
|||
int median = getMedian(width * height, histo); |
|||
System.out.println("histogram size =:" + histo.length ); |
|||
BufferedImage bwimg = new BufferedImage(width, height, img.getType()); |
|||
for (int y = 0; y < height; y++) { |
|||
for (int |
for (int x = 0; x < width; x++) { |
||
bwimg.setRGB(x, y, luminance(img.getRGB(x, y)) >= median ? 0xFFFFFFFF : 0xFF000000); |
|||
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]; |
|||
return bwimg; |
|||
} |
|||
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]++; |
|||
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))]++; |
|||
} |
} |
||
} |
|||
if (hist.length != histo.length) { |
|||
return histo; |
|||
System.out.println("Error in histogram processing!\n" |
|||
} |
|||
+ "histogram size is wrong "); |
|||
return; |
|||
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]; |
|||
System.out.println("Error in histogram processing!\n" |
|||
median++; |
|||
+ "values are different (interv= " + i |
|||
} |
|||
+ " computed: " + histo[i] |
|||
return median; |
|||
+ " theorical :" + hist[i] + "\n"); |
|||
} |
|||
return; |
|||
}</lang> |
|||
} |
|||
} |
|||
} |
|||
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] ); |
|||
} |
|||
} |
|||
} |
|||
</lang> |
|||
=={{header|Julia}}== |
=={{header|Julia}}== |
||
<lang Julia> |
<lang Julia> |