package controller;
//----- JDK Imports ------------------------------------------------------------
import java.awt.image.WritableRaster;
import java.util.Vector;
//----- Quicktime Imports ------------------------------------------------------
import quicktime.std.movies.Movie;
//----- Phoenix Imports --------------------------------------------------------
import util.ImageUtils;
import view.HistogramWindow;
/**
* Video Phoenix
* Version 0.2.0
* Copyright (c) 2007 Lunderskov, Ian; Pan, Jiabei; Rebelsky, Samuel;
* Whisenhunt, Heather; Young, Ian; Zuleta Benavides, Luis.
* All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
* @author Pan, Jiabei; Rebelsky, Samuel; Whisenhunt, Heather
* @author Glimmer Labs
* @version 0.2.0
*/
public class HistogramController
{
/*--------*-------------------------------------------------------------------
* Fields *
*--------*/
// vector of windows for this controller
public Vector<HistogramWindow> windows;
// this controller's instance of Phoenix
public PhoenixController phoenix;
/*--------------*-------------------------------------------------------------
* Constructors *
*--------------*/
/**
* Create a new HistogramController
*
* @param phoenix PhoenixController for this HistogramController
*/
public HistogramController(PhoenixController phoenix)
{
this.phoenix = phoenix;
this.windows = new Vector<HistogramWindow>();
} // HistogramController(PhoenixController)
/*---------*------------------------------------------------------------------
* Methods *
*---------*/
/**
* Create a new HistogramWindow with this controller
*
* @param title Title of the HistogramWindow
* @param data Histogram data
* @param channel Color channel (e.g., "h", "s", "v", "rgb", "r", ...)
*/
public void showHistogram(int[] data, String channel, float time)
{
HistogramWindow histogramWindow = new HistogramWindow(this,
channel.toUpperCase() + " - " + String.valueOf(time),
data, channel);
this.windows.add(histogramWindow);
} // showHistogram(String, int[], String)
/**
* Convert RGB data into HSV data
*
* @param rgb R, G, and B values to be converted to HSV
* @return hsv HSV equivalent of the data in rgb
*/
public int[] RGBtoHSV(int[] rgb)
{
int[] hsv = new int[3];
float varR = ((float) rgb[0]) / 255;
float varG = ((float) rgb[1]) / 255;
float varB = ((float) rgb[2]) / 255;
float hue = 0;
float sat = 0;
float val = 0;
float f = 0;
float l = 0;
float varMin = Math.min(Math.min(varR, varG), varB);
float varMax = Math.max(Math.max(varR, varG), varB);
if (varMax == varMin)
{
hue = 0;
sat = 0;
} // if (varMax == varMin)
else
{
if (varR == varMin)
{
f = varG - varB;
l = 3.0f;
} // if (varR == varMin)
else if (varG == varMin)
{
f = varB - varR;
l = 5.0f;
} // else if (varG == varMin)
else if (varB == varMin)
{
f = varR - varG;
l = 1.0f;
} // else if (varB == varMin)
hue = (l - f / (varMax - varMin)) * 60;
sat = ((varMax - varMin) / varMax) * 100;
} // else
val = varMax * 100;
hsv[0] = (Math.round(hue))%360;
hsv[1] = (Math.round(sat))%100;
hsv[2] = (Math.round(val))%100;
return hsv;
} // RGBtoHSV(int[])
/**
* Get histogram data for a movie frame
*
* @param mov Movie to obtain histogram data from
* @param time Time in the movie to obtain histogram data
* @param channel Color channel (e.g., "h", "s", "v", "rgb", "r", ...)
* @return data Histogram data for the frame
*/
public int[] getHistogramData(Movie mov, float time, String channel)
{
if ((channel.equalsIgnoreCase("h")) || (channel.equalsIgnoreCase("s"))
|| (channel.equalsIgnoreCase("v")))
{
return this.getHSVHistogramData(mov, time, channel);
} // if (channel.equalsIgnoreCase("hsv")) || ...
else
{
return this.getRGBHistogramData(mov, time, channel);
} // else
} // getHistogramData(Movie, float, String)
/* get HSV histogram data for <channel> from <mov> at <time> */
private int[] getHSVHistogramData(Movie mov, float time, String channel)
{
WritableRaster raster = ImageUtils.makeRaster(mov, time);
return getHSVHistogramData(raster, channel, 0, raster.getWidth(), 0,
raster.getHeight());
} // getHSVHistogramData(Movie, float, String)
/* get RGB histogram data for <channel> from <mov> at <time> */
private int[] getRGBHistogramData(Movie mov, float time, String channel)
{
WritableRaster raster = ImageUtils.makeRaster(mov, time);
return getRGBHistogramData(raster, channel, 0, raster.getWidth(), 0,
raster.getHeight());
} // getRGBHistogramData(Movie, float, String)
/**
* Get histogram data for a selection of a movie frame
*
* @param mov Movie to obtain histogram data from
* @param time Time in the movie to obtain histogram data
* @param channel Color channel (e.g., "rgb", "r", "h", "s", "v", ...)
* @param left Left edge of the selection in pixels (inclusive)
* @param right Right edge of the selection in pixels (exclusive)
* @param top Top edge of the selection in pixels (inclusive)
* @param bottom Bottom edge of the selection in pixels (exclusive)
* @return data Histogram data for the selection
*/
public int[] getHistogramData(Movie mov, float time, String channel, int left,
int right, int top, int bottom)
{
if ((channel.equalsIgnoreCase("h")) || (channel.equalsIgnoreCase("s"))
|| (channel.equalsIgnoreCase("v")))
{
return this.getHSVHistogramData(mov, time, channel, left, right, top,
bottom);
} // if (channel.equalsIgnoreCase("h")) || ...
else
{
return this.getRGBHistogramData(mov, time, channel, left, right, top,
bottom);
} // else
} // getHistogramData(Movie, float, String, int, int, int, int)
/* get HSV histogram data for a selection from <mov> at <time> */
private int[] getHSVHistogramData(Movie mov, float time, String channel,
int left, int right, int top, int bottom)
{
WritableRaster raster = ImageUtils.makeRaster(mov, time);
return this.getHSVHistogramData(raster, channel, left, right, top, bottom);
} // getHSVHistogramData(Movie, float, String, int, int, int, int)
/* get RGB histogram data for a selection from <mov> at <time> */
private int[] getRGBHistogramData(Movie mov, float time, String channel,
int left, int right, int top, int bottom)
{
WritableRaster raster = ImageUtils.makeRaster(mov, time);
return this.getRGBHistogramData(raster, channel, left, right, top, bottom);
} // getRGBHistogramData(Movie, float, String, int, int, int, int)
/**
* Get histogram data for a selection of a WritableRaster
*
* @param raster WritableRaster to obtain histogram data from
* @param channel Color channel (e.g., "rgb", "r", "h", "s", "v", ...)
* @param left Left edge of the selection (inclusive)
* @param right Right edge of the selection (exclusive)
* @param top Top edge of the selection (inclusive)
* @param bottom Bottom edge of the selection (exclusive)
* @return data HSistogram data for the selection
*/
public int[] getHistogramData(WritableRaster raster, String channel, int left,
int right, int top, int bottom)
{
if ((channel.equalsIgnoreCase("h")) || (channel.equalsIgnoreCase("s"))
|| (channel.equalsIgnoreCase("v")))
{
return this.getHSVHistogramData(raster, channel, left, right, top,
bottom);
} // if (channel.equalsIgnoreCase("h")) || ...
else
{
return this.getRGBHistogramData(raster, channel, left, right, top,
bottom);
} // else
} // getHistogramData(WritableRaster, String, int, int, int, int)
/* get HSV histogram data from a selection of <raster> */
private int[] getHSVHistogramData(WritableRaster raster, String channel,
int left, int right, int top, int bottom)
{
int numBins = 0;
int chan = 0;
if (channel.equalsIgnoreCase("h"))
{
chan = 0;
numBins = 360;
} // if (channel.equalsIgnoreCase("h"))
else if (channel.equalsIgnoreCase("s"))
{
chan = 1;
numBins = 101;
} // else if (channel.equalsIgnoreCase("s"))
else
{
chan = 2;
numBins = 101;
} // else
int[] bins = new int[numBins];
// calculate hue of each pixel from RGB data
int[] data = new int[4];
for (int i = left; i < right; i++)
{
for (int j = top; j < bottom; j++)
{
raster.getPixel(i, j, data);
// put this pixel's data into bins
bins[(Math.round(RGBtoHSV(data)[chan])) % numBins]++;
} // for
} // for
return bins;
} // getHSVHistogramData(WritableRaster, String, int, int, int, int)
/* get RGB histogram data from a selection of <raster> */
private int[] getRGBHistogramData(WritableRaster raster, String channel,
int left, int right, int top, int bottom)
{
int[] bins = new int[256];
int[] data = new int[4];
int lum = 0;
for (int i = left; i < right; i++)
{
for (int j = top; j < bottom; j++)
{
data[0] = 0;
data[1] = 0;
data[2] = 0;
data[3] = 0;
raster.getPixel(i, j, data);
// if channel is rgb, use weighted average of colors
if (channel.equalsIgnoreCase("rgb"))
{
lum = (int) java.lang.Math.round((data[0]) * 0.299
+ (data[1]) * 0.587
+ (data[2]) * 0.114);
} // if (channel.equalsIgnoreCase("rgb"))
// if only one color, use that color as luminance measure
else if (channel.equalsIgnoreCase("r"))
{
lum = data[0];
} // else if (channel.equals.IgnoreCase("r"))
else if (channel.equalsIgnoreCase("g"))
{
lum = data[1];
} // else if (channel.equalsIgnoreCase("g"))
else if (channel.equalsIgnoreCase("b"))
{
lum = data[2];
} // else if (channel.equalsIgnoreCase("b"))
// put this pixel's data into bins
bins[lum]++;
} // for
} // for
return bins;
} // getRGBHistogramData(WritableRaster, String, int, int, int, int)
/**
* Find the maximum value in an array
*
* @param array Array to find maximum value
* @return max Maximum value in array
*/
public static int getMax(int[] array)
{
int max = -1;
int length = array.length;
for (int i = 0; i < length; i++)
{
if (max < array[i])
{
max = array[i];
} // if (max < array[i])
} // for
return max;
} // getMax(int[])
} // class HistogramController