/*
* Copyright 2011 Jon A. Webb
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package root.gast.playground.image.detectlogobetter;
import jjil.algorithm.Gray8ConnComp;
import jjil.algorithm.Gray8HistEq;
import jjil.algorithm.Gray8Reduce;
import jjil.algorithm.Gray8Rgb;
import jjil.algorithm.Gray8Threshold;
import jjil.android.DebugImage;
import jjil.android.Nv212RgbImage;
import jjil.android.RgbImageAndroid;
import jjil.core.Error;
import jjil.core.Image;
import jjil.core.PipelineStage;
import jjil.core.Rect;
import jjil.core.RgbImage;
import jjil.core.Sequence;
import root.gast.image.ImageCameraView;
import root.gast.image.LogoView;
import android.graphics.Color;
import android.graphics.ImageFormat;
import android.graphics.RectF;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.widget.ImageView.ScaleType;
public class DetectLogo implements android.hardware.Camera.PreviewCallback
{
private static final int MIN_LOGO_SIZE = 50;
private FindBrightestPoint mFbp;
private Gray8ConnComp mG8cc;
private PipelineStage mDisplay;
private LogoView mLogoView;
private RgbAbsDiffGrayWb mRadg;
private Sequence mSeqThreshold;
private ImageCameraView mImageView;
public DetectLogo(ImageCameraView view, LogoView lv) throws jjil.core.Error
{
mImageView = view;
mLogoView = lv;
mImageView.setScaleType(ScaleType.FIT_XY);
// calculate the absolute value of the difference between the RGB value
// and magenta
// a small number here corresponds to a greenish pixel
mRadg = new RgbAbsDiffGrayWb(Color.GREEN);
// then we reduce the image size
Gray8Reduce g8r;
g8r = new Gray8Reduce(2, 2);
// then pass all pixels less than -96
Gray8Threshold g8t = new Gray8Threshold(-96, true);
// Now build the pipeline
mSeqThreshold = new Sequence(mRadg);
mSeqThreshold.add(g8r);
mSeqThreshold.add(new Gray8HistEq());
mSeqThreshold.add(g8t);
mG8cc = new Gray8ConnComp();
// for measuring the brightest pixel in the scene
// we sample every 8th pixel horizontally and vertically
mFbp = new FindBrightestPoint(8, 8);
// for converting thresholded output for display
// we have to model the rotation and mirroring applied to
// the image when it is oriented with Camera.setDisplayOrientation()
mDisplay = new Gray8Rgb();
}
@Override
public void onPreviewFrame(byte[] data, Camera camera)
{
Parameters cameraParameters = camera.getParameters();
int imageFormat = cameraParameters.getPreviewFormat();
// we only know how to process NV21 format (the default format)
if (imageFormat == ImageFormat.NV21)
{
Size size = camera.getParameters().getPreviewSize();
/**
* for debugging purposes, allow the current image to be saved and
* reused
*/
boolean bWrite = false, bRead = false;
Integer width = size.width, height = size.height;
if (bWrite)
{
DebugImage.writeNv21Image(data, width, height, "logo.png");
}
if (bRead)
{
DebugImage.Nv21Image nv21Image = DebugImage
.readImage2Nv21("logo.png");
width = nv21Image.getWidth();
height = nv21Image.getHeight();
data = nv21Image.getData();
}
// first convert to an RGB image for processing
RgbImage rgb = Nv212RgbImage
.getRgbImageReduced(data, width, height);
// get the brightest pixel for white balance
mFbp.push(rgb);
int nBrightestColor = mFbp.getBrightestColor();
// pass the white balance color
mRadg.setWhiteBalance(nBrightestColor);
// next push the rgb image into the pre-built pipeline
try
{
mSeqThreshold.push(rgb);
Image imThresholded = mSeqThreshold.getFront();
// no need to make a copy here, neither PipelineStage
// modifies its input
mDisplay.push(imThresholded);
// show the thresholded image
RgbImage imDisplay = (RgbImage) mDisplay.getFront();
mImageView.setImageBitmap(RgbImageAndroid.toBitmap(imDisplay));
mImageView.invalidate();
mG8cc.push(imThresholded);
// calculate connected components. We make this a member
// variable
// so we can access the connected components
// take the largest connected component
int nBestCompactness = Integer.MAX_VALUE, nBestComponent = -1;
for (int i = 0; i < mG8cc.getComponentCount()
&& mG8cc.getPixelCount(i) > MIN_LOGO_SIZE; i++)
{
int perimeter = mG8cc.getPerimeter(i);
int area = mG8cc.getPixelCount(i);
int compactness = perimeter * perimeter / area;
if (compactness < nBestCompactness)
{
nBestCompactness = compactness;
nBestComponent = i;
}
}
if (nBestComponent != -1)
{
Rect r = mG8cc.getComponent(nBestComponent);
RectF rf = new RectF(r.getLeft(), r.getTop(), r.getRight(), r.getBottom());
mLogoView.setRect(rf);
} else {
mLogoView.clearRect();
}
} catch (Error e)
{
}
}
}
}