/*! Copyright (C) 2009 Apertus, All Rights Reserved
*! Author : Apertus Team
-----------------------------------------------------------------------------**
*!
*! This program is free software: you can redistribute it and/or modify
*! it under the terms of the GNU General Public License as published by
*! the Free Software Foundation, either version 3 of the License, or
*! (at your option) any later version.
*!
*! This program is distributed in the hope that it will be useful,
*! but WITHOUT ANY WARRANTY; without even the implied warranty of
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! GNU General Public License for more details.
*!
*! You should have received a copy of the GNU General Public License
*! along with this program. If not, see <http://www.gnu.org/licenses/>.
*!
-----------------------------------------------------------------------------**/
import java.awt.*;
import javax.swing.JPanel;
public class Histogram extends JPanel implements Runnable, java.io.Serializable {
int width, height;
int i = 0;
Thread animator;
int fps = 10;
ElphelVision Parent = null;
public Histogram() {
//width = width + 2;
//height = 50;
}
public Histogram(ElphelVision parent) {
this.Parent = parent;
//width = width + 2;
//height = 50;
}
public void SetParent(ElphelVision parent) {
this.Parent = parent;
}
public void startAnimator() {
animator = new Thread(this);
animator.start();
//setSize(width, height);
}
public void StopAnimator() {
animator.interrupt();
//setSize(width, height);
}
public void run() {
while (Thread.currentThread() == animator) {
repaint();
try {
Thread.sleep((int) (1.0f / fps * 1000.0f));
} catch (InterruptedException e) {
break;
}
}
}
public int GetMin(Color channel) {
int treshhold = 5; // if value is below treshhold we do not account for it to minimize noise influence
int[][] hist_value = Parent.Camera.GetHistogram(0);
int ret = 255;
if (channel == Color.red) {
for (int i = 0; i < hist_value[0].length; i++) {
if (hist_value[0][i] > treshhold) {
ret = i;
break;
}
}
}
if (channel == Color.green) {
for (int i = 0; i < hist_value[1].length; i++) {
if (hist_value[1][i] > treshhold) {
ret = i;
break;
}
}
}
if (channel == Color.blue) {
for (int i = 0; i < hist_value[2].length; i++) {
if (hist_value[2][i] > treshhold) {
ret = i;
break;
}
}
}
return ret;
}
public int GetMax(Color channel) {
int treshhold = 5; // if value is above treshhold we do not account for it to minimize noise influence
int[][] hist_value = Parent.Camera.GetHistogram(0);
int ret = 255;
if (channel == Color.red) {
for (int i = hist_value[0].length - 1; i >= 0; i--) {
if (hist_value[0][i] > treshhold) {
ret = i;
break;
}
}
}
if (channel == Color.green) {
for (int i = hist_value[1].length - 1; i >= 0; i--) {
if (hist_value[1][i] > treshhold) {
ret = i;
break;
}
}
}
if (channel == Color.blue) { // blue
for (int i = hist_value[2].length - 1; i >= 0; i--) {
if (hist_value[2][i] > treshhold) {
ret = i;
break;
}
}
}
return ret;
}
@Override
public void paint(Graphics g) {
super.paint(g);
width = this.getWidth();
height = this.getHeight();
if (this.Parent != null) {
int[][] hist_value = Parent.Camera.GetHistogram(0);
Graphics2D g2 = (Graphics2D) g;
g.setPaintMode();
//range background
//10%
g.setColor(new Color(5, 5, 5));
g.fillRect(0, 0, width / 10, height - 9);
// 30%
g.setColor(new Color(15, 15, 15));
g.fillRect(width / 10, 0, 3 * width / 10, height - 9);
// 50%
g.setColor(new Color(20, 20, 20));
g.fillRect(3 * width / 10, 0, 5 * width / 10, height - 9);
// 70%
g.setColor(new Color(25, 25, 25));
g.fillRect(5 * width / 10, 0, 7 * width / 10, height - 9);
// 90%
g.setColor(new Color(30, 30, 30));
g.fillRect(7 * width / 10, 0, 9 * width / 10, height - 9);
// 100%
g.setColor(new Color(50, 50, 50));
g.fillRect(9 * width / 10, 0, 10 * width / 10, height - 9);
// range indicators
g.setColor(new Color(35, 35, 35));
g2.drawLine(width / 10, 0, width / 10, height - 9);
g.setColor(new Color(40, 40, 40));
g2.drawLine(3 * width / 10, 0, 3 * width / 10, height - 9);
g.setColor(new Color(45, 45, 45));
g2.drawLine(5 * width / 10, 0, 5 * width / 10, height - 9);
g.setColor(new Color(50, 50, 50));
g2.drawLine(7 * width / 10, 0, 7 * width / 10, height - 9);
g.setColor(new Color(70, 70, 70));
g2.drawLine(9 * width / 10, 0, 9 * width / 10, height - 9);
// gradient
int GradientHeight = 2;
Color c1 = Color.black;
Color c2 = Color.white;
GradientPaint gradient = new GradientPaint(0, 0, c1, width, 0, c2, false);
g2.setPaint(gradient);
g2.fillRect(0, height - 8, width, GradientHeight);
// min/max indicators
//red
g2.setStroke(new BasicStroke(2));
g.setColor(new Color(255, 0, 0));
g2.drawLine(GetMin(Color.red) * width / hist_value[2].length, height - 6, GetMax(Color.red) * width / hist_value[2].length, height - 6);
//green
g.setColor(new Color(0, 255, 0));
g2.drawLine(GetMin(Color.green) * width / hist_value[2].length, height - 4, GetMax(Color.green) * width / hist_value[2].length, height - 4);
//blue
g.setColor(new Color(0, 0, 255));
g2.drawLine(GetMin(Color.blue) * width / hist_value[2].length, height - 2, GetMax(Color.blue) * width / hist_value[2].length, height - 2);
// coordinate system
g2.setStroke(new BasicStroke(1));
g2.setColor(Color.darkGray);
g2.drawLine(0, height - 9, width - 1, height - 9);
g2.drawLine(width - 1, height - 9, width - 1, 0);
g2.drawLine(width - 1, 0, 0, 0);
g2.drawLine(0, 0, 0, height - 9);
//draw actual histogram bars
// Why does this not work in a single loop? weird behaviour...
g2.setStroke(new BasicStroke(width / hist_value[2].length));
if (Parent.Camera.GetHistogramColorMode() == HistogramColorMode.RGB) {
for (int i = 0; i < hist_value[2].length / 2; i++) {
int helper = 127 + i / 2;
// RED
Color RedGradient = new Color(helper, 0, 0);
g2.setColor(RedGradient);
g2.drawLine(i * width / hist_value[2].length, height - 9, i * width / hist_value[2].length, height - 9 - (hist_value[0][i] * (height - 9) / hist_value[2].length));
// GREEN
Color GreenGradient = new Color(0, helper, 0);
g2.setColor(GreenGradient);
g2.drawLine(i * width / hist_value[2].length, height - 9, i * width / hist_value[2].length, height - 9 - (hist_value[1][i] * (height - 9) / hist_value[2].length));
// BLUE
Color BlueGradient = new Color(0, 0, helper);
g2.setColor(BlueGradient);
g2.drawLine(i * width / hist_value[2].length, height - 9, i * width / hist_value[2].length, height - 9 - (hist_value[2][i] * (height - 9) / hist_value[2].length));
//YELLOW
if ((hist_value[1][i] > hist_value[2][i]) && (hist_value[0][i] > hist_value[2][i])) {
Color YellowGradient = new Color(helper, helper, 0);
g2.setColor(YellowGradient);
if (hist_value[1][i] > hist_value[0][i]) {
int valueheight = hist_value[0][i] * height / 256;
g2.drawLine(i * width / hist_value[2].length, height - 9, i * width / hist_value[2].length, height - 9 - (valueheight * (height - 9) / hist_value[2].length));
} else {
int valueheight = hist_value[1][i] * height / 256;
g2.drawLine(i * width / hist_value[2].length, height - 9, i * width / hist_value[2].length, height - 9 - (valueheight * (height - 9) / hist_value[2].length));
}
}
//PINK
if ((hist_value[2][i] > hist_value[1][i]) && (hist_value[0][i] > hist_value[1][i])) {
Color PinkGradient = new Color(helper, 0, helper);
g2.setColor(PinkGradient);
if (hist_value[2][i] > hist_value[0][i]) {
g2.drawLine(i * width / hist_value[2].length, height - 9, i * width / hist_value[2].length, height - 9 - (hist_value[0][i] * (height - 9) / hist_value[2].length));
} else {
g2.drawLine(i * width / hist_value[2].length, height - 9, i * width / hist_value[2].length, height - 9 - (hist_value[2][i] * (height - 9) / hist_value[2].length));
}
}
//CYAN
if ((hist_value[2][i] > hist_value[0][i]) && (hist_value[1][i] > hist_value[0][i])) {
Color CyanGradient = new Color(0, helper, helper);
g2.setColor(CyanGradient);
if (hist_value[2][i] > hist_value[1][i]) {
g2.drawLine(i * width / hist_value[2].length, height - 9, i * width / hist_value[2].length, height - 9 - (hist_value[1][i] * (height - 9) / hist_value[2].length));
} else {
g2.drawLine(i * width / hist_value[2].length, height - 9, i * width / hist_value[2].length, height - 9 - (hist_value[2][i] * (height - 9) / hist_value[2].length));
}
}
// WHITE
int lowest = 999999999;
if ((hist_value[0][i] * (height - 9) / width) < lowest) {
lowest = hist_value[0][i] * (height - 9) / hist_value[2].length;
}
if ((hist_value[1][i] * (height - 9) / width) < lowest) {
lowest = hist_value[1][i] * (height - 9) / hist_value[2].length;
}
if ((hist_value[2][i] * (height - 9) / width) < lowest) {
lowest = hist_value[2][i] * (height - 9) / hist_value[2].length;
}
Color WhiteGradient = new Color(helper, helper, helper);
g2.setColor(WhiteGradient);
g2.drawLine(i * width / hist_value[2].length, height - 9, i * width / hist_value[2].length, height - 9 - lowest);
}
for (int j = 128; j < hist_value[2].length; j++) {
int helper = 127 + j / 2;
// RED
Color RedGradient = new Color(helper, 0, 0);
g2.setColor(RedGradient);
g2.drawLine(j * width / hist_value[2].length, height - 9, j * width / hist_value[2].length, height - 9 - (hist_value[0][j] * (height - 9) / hist_value[2].length));
// GREEN
Color GreenGradient = new Color(0, helper, 0);
g2.setColor(GreenGradient);
g2.drawLine(j * width / hist_value[2].length, height - 9, j * width / hist_value[2].length, height - 9 - (hist_value[1][j] * (height - 9) / hist_value[2].length));
// BLUE
Color BlueGradient = new Color(0, 0, helper);
g2.setColor(BlueGradient);
g2.drawLine(j * width / hist_value[2].length, height - 9, j * width / hist_value[2].length, height - 9 - (hist_value[2][j] * (height - 9) / hist_value[2].length));
//YELLOW
if ((hist_value[1][j] > hist_value[2][j]) && (hist_value[0][j] > hist_value[2][j])) {
Color YellowGradient = new Color(helper, helper, 0);
g2.setColor(YellowGradient);
if (hist_value[1][j] > hist_value[0][j]) {
g2.drawLine(j * width / hist_value[2].length, height - 9, j * width / hist_value[2].length, height - 9 - (hist_value[0][j] * (height - 9) / hist_value[2].length));
} else {
g2.drawLine(j * width / hist_value[2].length, height - 9, j * width / hist_value[2].length, height - 9 - (hist_value[1][j] * (height - 9) / hist_value[2].length));
}
}
//PINK
if ((hist_value[2][j] > hist_value[1][j]) && (hist_value[0][j] > hist_value[1][j])) {
Color PinkGradient = new Color(helper, 0, helper);
g2.setColor(PinkGradient);
if (hist_value[2][j] > hist_value[0][j]) {
g2.drawLine(j * width / hist_value[2].length, height - 9, j * width / hist_value[2].length, height - 9 - (hist_value[0][j] * (height - 9) / hist_value[2].length));
} else {
g2.drawLine(j * width / hist_value[2].length, height - 9, j * width / hist_value[2].length, height - 9 - (hist_value[2][j] * (height - 9) / hist_value[2].length));
}
}
//CYAN
if ((hist_value[2][j] > hist_value[0][j]) && (hist_value[1][j] > hist_value[0][j])) {
Color CyanGradient = new Color(0, helper, helper);
g2.setColor(CyanGradient);
if (hist_value[2][j] > hist_value[1][j]) {
g2.drawLine(j * width / hist_value[2].length, height - 9, j * width / hist_value[2].length, height - 9 - (hist_value[1][j] * (height - 9) / hist_value[2].length));
} else {
g2.drawLine(j * width / hist_value[2].length, height - 9, j * width / hist_value[2].length, height - 9 - (hist_value[2][j] * (height - 9) / hist_value[2].length));
}
}
// WHITE
int lowest = 999999999;
if ((hist_value[0][j] * (height - 9) / width) < lowest) {
lowest = hist_value[0][j] * (height - 9) / hist_value[2].length;
}
if ((hist_value[1][j] * (height - 9) / width) < lowest) {
lowest = hist_value[1][j] * (height - 9) / hist_value[2].length;
}
if ((hist_value[2][j] * (height - 9) / width) < lowest) {
lowest = hist_value[2][j] * (height - 9) / hist_value[2].length;
}
Color WhiteGradient = new Color(helper, helper, helper);
g2.setColor(WhiteGradient);
g2.drawLine(j * width / hist_value[2].length, height - 9, j * width / hist_value[2].length, height - 9 - lowest);
}
} else if (Parent.Camera.GetHistogramColorMode() == HistogramColorMode.LUMINOSITY) {
for (int i = 0; i < hist_value[2].length; i++) {
int helper = 127 + i / 2;
Color WhiteGradient = new Color(helper, helper, helper);
g2.setColor(WhiteGradient);
g2.drawLine(i * width / hist_value[2].length, height - 9, i * width / hist_value[2].length, height - 9 - (hist_value[0][i] * (height - 9) / hist_value[2].length));
}
}
} else {
// draw something so the area in the GUI designer isnt just black
Graphics2D g2 = (Graphics2D) g;
g.setPaintMode();
g.setColor(new Color(5, 5, 5));
g.fillRect(0, 0, width, height);
// TODO doesnt work....why not
}
}
public void stop() {
animator = null;
}
}