/*
* Artcodes recognises a different marker scheme that allows the
* creation of aesthetically pleasing, even beautiful, codes.
* Copyright (C) 2013-2016 The University of Nottingham
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package uk.ac.horizon.artcodes.process;
import android.content.Context;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.CvType;
import org.opencv.imgproc.Imgproc;
import java.util.List;
import java.util.Map;
import uk.ac.horizon.artcodes.detect.DetectorSetting;
import uk.ac.horizon.artcodes.detect.ImageBuffers;
import uk.ac.horizon.artcodes.detect.handler.MarkerDetectionHandler;
import uk.ac.horizon.artcodes.model.Experience;
public class HlsEditImageProcessor implements ImageProcessor
{
public static class HlsEditImageProcessorFactory implements ImageProcessorFactory
{
@Override
public String getName()
{
return "hlsEdit";
}
private static final String[] HUE_KEYS = {"hue", "hueShift", "h"};
private static final String[] LIGHTNESS_KEYS = {"lightness", "l"};
private static final String[] SATURATION_KEYS = {"saturation", "s"};
@Override
public ImageProcessor create(Context context, Experience experience, MarkerDetectionHandler handler, Map<String, String> args)
{
int hueShift=0, lightnessAddition=0, saturationAddition=0;
if (args != null)
{
for (String key : HUE_KEYS)
{
if (args.containsKey(key))
{
hueShift = Integer.parseInt(args.get(key));
}
}
for (String key : LIGHTNESS_KEYS)
{
if (args.containsKey(key))
{
lightnessAddition = Integer.parseInt(args.get(key));
}
}
for (String key : SATURATION_KEYS)
{
if (args.containsKey(key))
{
saturationAddition = Integer.parseInt(args.get(key));
}
}
}
return new HlsEditImageProcessor(hueShift, lightnessAddition, saturationAddition);
}
}
protected final int hueShift, lightnessAddition, saturationAddition;
protected final Mat lut;
public HlsEditImageProcessor(int hueShift, int lightnessAddition, int saturationAddition)
{
// hue input range: [0,360] change to range: [0,180]
this.hueShift = (hueShift / 2) % 181;
// lightness input range: [-100,100] change to range: [-255,255]
this.lightnessAddition = Math.min(Math.max((int) (lightnessAddition*2.55),-255),255);
// saturation input range: [-100,100] change to range: [-255,255]
this.saturationAddition = Math.min(Math.max((int) (saturationAddition*2.55),-255),255);
float lightnessMultiplyer = ((this.lightnessAddition+255.0f)/255.0f);
float saturationMultiplyer = ((this.lightnessAddition+255.0f)/255.0f);
this.lut = new Mat(1, 256, CvType.CV_8UC3);
int lutSize = lut.cols() * lut.rows() * lut.channels();
byte[] lutBuffer = new byte [lutSize];
for (int i=0, lutIndex = -1; i<256; ++i)
{
lutBuffer[++lutIndex] = (byte) (((i)+this.hueShift)%181);
lutBuffer[++lutIndex] = (byte) Math.min(Math.max(
(int) ((i) * lightnessMultiplyer)
, 0), 255);
lutBuffer[++lutIndex] = (byte) Math.min(Math.max(
(int) ((i) * saturationMultiplyer)
, 0), 255);
}
lut.put(0, 0, lutBuffer);
}
@Override
public void process(ImageBuffers buffers)
{
if (this.hueShift!=0 || this.lightnessAddition!=0 || this.saturationAddition!=0)
{
// Convert to HLS:
Mat threeChannelBuffer = buffers.getImageInBgr();
Imgproc.cvtColor(threeChannelBuffer, threeChannelBuffer, Imgproc.COLOR_BGR2HLS);
// Apply look-up-table:
Core.LUT(threeChannelBuffer, lut, threeChannelBuffer);
// Convert back to BGR:
Imgproc.cvtColor(threeChannelBuffer, threeChannelBuffer, Imgproc.COLOR_HLS2BGR);
buffers.setImage(threeChannelBuffer);
}
}
@Override
public void getSettings(List<DetectorSetting> settings)
{
}
public void release()
{
this.lut.release();
}
}