/*
* HaoRan ImageFilter Classes v0.4
* Copyright (C) 2012 Zhenjun Dai
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* This library 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation.
*/
package com.marshalchen.common.uimodule.ImageFilter;
public class YCBCrLinearFilter implements IImageFilter{
static class MyColor{
public int R;
public int G;
public int B;
public MyColor(){}
public MyColor(int r, int g, int b){
R = r;
G = g;
B = b;
}
public MyColor(int rgb){
R = ((rgb& 0x00FF0000) >> 16);
G = ((rgb& 0x0000FF00) >> 8);
B = ( rgb& 0x000000FF);
}
static int rgb(int r, int g, int b){
return (255 << 24) + (r << 16) + (g << 8) + b;
}
}
private Range inY = new Range(0.0f, 1.0f);
private Range inCb = new Range(-0.5f, 0.5f);
private Range inCr = new Range(-0.5f, 0.5f);
private Range outY = new Range(0.0f, 1.0f);
private Range outCb = new Range(-0.5f, 0.5f);
private Range outCr = new Range(-0.5f, 0.5f);
public YCBCrLinearFilter(Range inCb)
{
this.inCb = inCb;
}
public YCBCrLinearFilter(Range inCb, Range inCr)
{
this.inCb = inCb;
this.inCr = inCr;
}
public Image process(Image imageIn)
{
MyColor rgb = new MyColor();
YCbCr ycbcr = new YCbCr();
float ky = 0, by = 0;
float kcb = 0, bcb = 0;
float kcr = 0, bcr = 0;
// Y line parameters
if (inY.Max != inY.Min)
{
ky = (outY.Max - outY.Min) / (inY.Max - inY.Min);
by = outY.Min - ky * inY.Min;
}
// Cb line parameters
if (inCb.Max != inCb.Min)
{
kcb = (outCb.Max - outCb.Min) / (inCb.Max - inCb.Min);
bcb = outCb.Min - kcb * inCb.Min;
}
// Cr line parameters
if (inCr.Max != inCr.Min)
{
kcr = (outCr.Max - outCr.Min) / (inCr.Max - inCr.Min);
bcr = outCr.Min - kcr * inCr.Min;
}
for (int x = 0; x < imageIn.getWidth(); x++)
{
for (int y = 0; y < imageIn.getHeight(); y++)
{
rgb.R = imageIn.getRComponent(x, y);
rgb.G = imageIn.getGComponent(x, y);
rgb.B = imageIn.getBComponent(x, y);
// convert to YCbCr
ycbcr = YCbCr.FromRGB(rgb, ycbcr);
// correct Y
if (ycbcr.Y >= inY.Max)
ycbcr.Y = outY.Max;
else if (ycbcr.Y <= inY.Min)
ycbcr.Y = outY.Min;
else
ycbcr.Y = ky * ycbcr.Y + by;
// correct Cb
if (ycbcr.Cb >= inCb.Max)
ycbcr.Cb = outCb.Max;
else if (ycbcr.Cb <= inCb.Min)
ycbcr.Cb = outCb.Min;
else
ycbcr.Cb = kcb * ycbcr.Cb + bcb;
// correct Cr
if (ycbcr.Cr >= inCr.Max)
ycbcr.Cr = outCr.Max;
else if (ycbcr.Cr <= inCr.Min)
ycbcr.Cr = outCr.Min;
else
ycbcr.Cr = kcr * ycbcr.Cr + bcr;
// convert back to RGB
rgb = YCbCr.ToRGB(ycbcr, rgb);
imageIn.setPixelColor(x, y, rgb.R, rgb.G, rgb.B);
}
}
return imageIn;
}
/// <summary>
/// YCbCr components.
/// </summary>
///
/// <remarks>The class encapsulates <b>YCbCr</b> color components.</remarks>
///
public static class YCbCr
{
/// <summary>
/// Index of <b>Y</b> component.
/// </summary>
public short YIndex = 0;
/// <summary>
/// Index of <b>Cb</b> component.
/// </summary>
public short CbIndex = 1;
/// <summary>
/// Index of <b>Cr</b> component.
/// </summary>
public short CrIndex = 2;
/// <summary>
/// <b>Y</b> component.
/// </summary>
public float Y;
/// <summary>
/// <b>Cb</b> component.
/// </summary>
public float Cb;
/// <summary>
/// <b>Cr</b> component.
/// </summary>
public float Cr;
/// <summary>
/// Initializes a new instance of the <see cref="YCbCr"/> class.
/// </summary>
public YCbCr() { }
/// <summary>
/// Initializes a new instance of the <see cref="YCbCr"/> class.
/// </summary>
///
/// <param name="y"><b>Y</b> component.</param>
/// <param name="cb"><b>Cb</b> component.</param>
/// <param name="cr"><b>Cr</b> component.</param>
///
public YCbCr(float y, float cb, float cr)
{
this.Y = Math.max(0.0f, Math.min(1.0f, y));
this.Cb = Math.max(-0.5f, Math.min(0.5f, cb));
this.Cr = Math.max(-0.5f, Math.min(0.5f, cr));
}
/// <summary>
/// Convert from RGB to YCbCr color space (Rec 601-1 specification).
/// </summary>
///
/// <param name="rgb">Source color in <b>RGB</b> color space.</param>
/// <param name="ycbcr">Destination color in <b>YCbCr</b> color space.</param>
///
public static YCbCr FromRGB(MyColor rgb, YCbCr ycbcr)
{
float r = (float)rgb.R / 255;
float g = (float)rgb.G / 255;
float b = (float)rgb.B / 255;
ycbcr.Y = (float)(0.2989 * r + 0.5866 * g + 0.1145 * b);
ycbcr.Cb = (float)(-0.1687 * r - 0.3313 * g + 0.5000 * b);
ycbcr.Cr = (float)(0.5000 * r - 0.4184 * g - 0.0816 * b);
return ycbcr;
}
/// <summary>
/// Convert from RGB to YCbCr color space (Rec 601-1 specification).
/// </summary>
///
/// <param name="rgb">Source color in <b>RGB</b> color space.</param>
///
/// <returns>Returns <see cref="YCbCr"/> instance, which represents converted color value.</returns>
///
public static YCbCr FromRGB(MyColor rgb)
{
YCbCr ycbcr = new YCbCr();
FromRGB(rgb, ycbcr);
return ycbcr;
}
/// <summary>
/// Convert from YCbCr to RGB color space.
/// </summary>
///
/// <param name="ycbcr">Source color in <b>YCbCr</b> color space.</param>
/// <param name="rgb">Destination color in <b>RGB</b> color spacs.</param>
///
public static MyColor ToRGB(YCbCr ycbcr, MyColor rgb)
{
// don't warry about zeros. compiler will remove them
float r = Math.max(0.0f, Math.min(1.0f, (float)(ycbcr.Y + 0.0000 * ycbcr.Cb + 1.4022 * ycbcr.Cr)));
float g = Math.max(0.0f, Math.min(1.0f, (float)(ycbcr.Y - 0.3456 * ycbcr.Cb - 0.7145 * ycbcr.Cr)));
float b = Math.max(0.0f, Math.min(1.0f, (float)(ycbcr.Y + 1.7710 * ycbcr.Cb + 0.0000 * ycbcr.Cr)));
rgb.R = (byte)(r * 255);
rgb.G = (byte)(g * 255);
rgb.B = (byte)(b * 255);
//rgb.Alpha = 255;
return rgb;
}
/// <summary>
/// Convert the color to <b>RGB</b> color space.
/// </summary>
///
/// <returns>Returns <see cref="RGB"/> instance, which represents converted color value.</returns>
///
public MyColor ToRGB()
{
MyColor rgb = new MyColor();
ToRGB(this, rgb);
return rgb;
}
}
public static class Range
{
public float Min, Max;
/// <summary>
/// Length of the range (deffirence between maximum and minimum values).
/// </summary>
public float Length()
{
return Max - Min;
}
/// <summary>
/// Initializes a new instance of the <see cref="Range"/> structure.
/// </summary>
///
/// <param name="min">Minimum value of the range.</param>
/// <param name="max">Maximum value of the range.</param>
///
public Range(float min, float max)
{
this.Min = min;
this.Max = max;
}
}
}