/*
* 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.Mat;
import org.opencv.core.Size;
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;
import uk.ac.horizon.artcodes.scanner.R;
public class TileThresholder implements ImageProcessor
{
public static class Factory implements ImageProcessorFactory
{
public String getName()
{
return "tile";
}
public ImageProcessor create(Context context, Experience experience, MarkerDetectionHandler handler, Map<String, String> args)
{
return new TileThresholder();
}
}
private enum Display
{
none, greyscale, threshold;
private static final Display[] vals = values();
public Display next()
{
return vals[(this.ordinal() + 1) % vals.length];
}
}
private transient int tiles = 1;
private Display display = Display.none;
public TileThresholder()
{
}
@Override
public void process(ImageBuffers buffers)
{
Mat image = buffers.getImageInGrey();
Imgproc.GaussianBlur(image, image, new Size(5, 5), 0);
if (display == Display.greyscale)
{
Imgproc.cvtColor(image, buffers.getOverlay(false), Imgproc.COLOR_GRAY2BGRA);
}
if (!buffers.hasDetected())
{
tiles = (tiles % 9) + 1;
}
final int tileHeight = (int) image.size().height / tiles;
final int tileWidth = (int) image.size().width / tiles;
// Split image into tiles and apply process on each image tile separately.
for (int tileRow = 0; tileRow < tiles; tileRow++)
{
final int startRow = tileRow * tileHeight;
int endRow;
if (tileRow < tiles - 1)
{
endRow = (tileRow + 1) * tileHeight;
}
else
{
endRow = (int) image.size().height;
}
for (int tileCol = 0; tileCol < tiles; tileCol++)
{
final int startCol = tileCol * tileWidth;
int endCol;
if (tileCol < tiles - 1)
{
endCol = (tileCol + 1) * tileWidth;
}
else
{
endCol = (int) image.size().width;
}
final Mat tileMat = image.submat(startRow, endRow, startCol, endCol);
Imgproc.threshold(tileMat, tileMat, 127, 255, Imgproc.THRESH_OTSU);
tileMat.release();
}
}
if (display == Display.threshold)
{
Imgproc.cvtColor(image, buffers.getOverlay(false), Imgproc.COLOR_GRAY2BGRA);
}
buffers.setImage(image);
}
@Override
public void getSettings(List<DetectorSetting> settings)
{
settings.add(new DetectorSetting()
{
@Override
public void nextValue()
{
display = display.next();
}
@Override
public int getIcon()
{
switch (display)
{
case none:
return R.drawable.ic_image_24dp;
case greyscale:
return R.drawable.ic_gradient_24dp;
case threshold:
return R.drawable.ic_filter_b_and_w_24dp;
}
return 0;
}
@Override
public int getText()
{
switch (display)
{
case none:
return R.string.draw_threshold_off;
case greyscale:
return R.string.draw_threshold_greyscale;
case threshold:
return R.string.draw_threshold_on;
}
return 0;
}
});
}
}