使用OpenCV在Java中反向投影

我想使用反投影检测图像中的特征与OpenCV

为了开始,我将非常乐意计算单个彩色小图像的直方图,然后将其应用于较大的图像。然后我可以建立更多的顶部。
有一个example in C++,我想在Java做这样的事情。
遗憾的是,OpenCV的Java接口没有很好的文档。

下面是我到目前为止的代码,但它不工作(显然,否则我不会要求帮助)。
这将是非常伟大的,如果有人可以帮助我得到它的工作或找到一些很好的文档Java API!

import java.util.ArrayList;
import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;

public class ColorHistogramDetector extends ColorThresholdDetector {
    //private cvHistogram histogram;
    //histogram resolution for hue and saturation
    static final int hbins = 30;//, sbins = 32;

    public synchronized Mat detect(Mat inputFrame) {
        Mat calcFrame = new Mat();
        Imgproc.cvtColor(inputFrame, calcFrame, Imgproc.COLOR_RGB2HSV);

        Mat hue = calcFrame;
        ArrayList<Mat> dst = new ArrayList<Mat>();
        dst.add(hue);

        //create single color image
        Mat fillImg = new Mat(16, 16, CvType.CV_8UC3);
        fillImg.setTo(hsvColor);

        MatOfInt histSize=new MatOfInt(hbins,hbins);

        // hue varies from 0 to 179, see cvtColor
        // saturation varies from 0 (black-gray-white) to
        // 255 (pure spectrum color)
        MatOfFloat ranges = new MatOfFloat( 0,180,0,256 );

        Mat hist = new Mat();

        // we compute the histogram from the 0-th and 1-st channels
        MatOfInt channels = new MatOfInt(0, 1);

        ArrayList<Mat> fillImgs=new ArrayList<Mat>();
        fillImgs.add(fillImg);
        Imgproc.calcHist(fillImgs, channels, new Mat(), hist, histSize, ranges);

        outputFrame = new Mat();

        Imgproc.calcBackProject(dst, channels, hist, calcFrame, ranges, 1);

        int w = inputFrame.cols(); int h = inputFrame.rows();
        int bin_w = (int) Math.round( (double) w / hbins );
        Mat histImg = new Mat( w, h, CvType.CV_8UC3 );

        for( int i = 0; i < hbins; i ++ ) { 
           Core.rectangle( histImg, new Point( i*bin_w, h ), 
                           new Point( (i+1)*bin_w, 
                           h - Math.round( hist.get(0, i)[0]*h/255.0 ) ), 
                           new Scalar( 0, 0, 255 ), -1 ); 
        }

        hist.release();
        fillImg.release();

        Imgproc.cvtColor(histImg, calcFrame, Imgproc.COLOR_RGB2HSV);

        return calcFrame;
    }
}
在你的代码中有一些奇怪的事情,所以我的建议是首先严格遵循教程,然后将其更改为你的用例。

你似乎在某种程度上接近你正在关注的教程,但它看起来像你正在应用calcHist到一个单一的彩色图像。我没有看到这是有用的,它通常应该是一个HSV图像与一些对象。此外,您缺少标准化步骤。

为了帮助你,我已经将C++ Back Projection Tutorial 转换为OpenCV4Android 2.4.8。

虽然您使用的是Java而不是Android,但API是完全相同的,只有样板输入/输出处理会有所不同。

Original C++ code can be found here.

对原始教程进行了一些非常小的更改,以使其更适用于Android,例如:

>它处理实时相机图像,而不是静态图像;
>使用触摸事件替换鼠标点击;
>背投影的输出显示在覆盖摄像机馈送的左上角;
>添加高斯模糊作为噪声降低。

我还没有测试所有的步骤彻底,但最终结果看起来确定。

注意:按原样,您需要触摸屏幕一次以初始化后投影…

这里是大部分,什么是缺少你可以找到here at GitHub

private int outputWidth=300;
private int outputHeight=200;
private Mat mOutputROI;

private boolean bpUpdated = false;

private Mat mRgba;
private Mat mHSV;
private Mat mask;

private int lo = 20; 
private int up = 20;

public void onCameraViewStarted(int width, int height) {

    mRgba = new Mat(height, width, CvType.CV_8UC3);
    mHSV = new Mat();
    mIntermediateMat = new Mat();
    mGray = new Mat(height, width, CvType.CV_8UC1);
    mOutputROI = new Mat(outputHeight, outputWidth, CvType.CV_8UC1);

    mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);        
}

public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
    Mat mCamera = inputFrame.rgba();

    Imgproc.cvtColor(mCamera, mRgba, Imgproc.COLOR_RGBA2RGB);

    Mat mOutputROI = mCamera.submat(0, outputHeight, 0, outputWidth);

    //Addition to remove some noise:
    Imgproc.GaussianBlur(mRgba, mRgba, new Size(5, 5), 0, Imgproc.BORDER_DEFAULT);

    Imgproc.cvtColor(mRgba, mHSV, Imgproc.COLOR_RGB2HSV_FULL);

    if(mask!=null){
        if(bpUpdated==false){
            mGray = histAndBackproj();
        } else {
            bpUpdated = false;
        }

        Imgproc.resize(mGray, mIntermediateMat, mOutputROI.size(), 0, 0, Imgproc.INTER_LINEAR);
        Imgproc.cvtColor(mIntermediateMat, mOutputROI, Imgproc.COLOR_GRAY2BGRA);
    }

    return mCamera;
}

public boolean onTouch(View arg0, MotionEvent arg1) {       
    Point seed = getImageCoordinates(mRgba, arg1.getX(), arg1.getY());

    int newMaskVal = 255;
    Scalar newVal = new Scalar( 120, 120, 120 );

    int connectivity = 8;
    int flags = connectivity + (newMaskVal << 8 ) + Imgproc.FLOODFILL_FIXED_RANGE + Imgproc.FLOODFILL_MASK_ONLY;

    Mat mask2 = Mat.zeros( mRgba.rows() + 2, mRgba.cols() + 2, CvType.CV_8UC1 );

    Rect rect = null;
    Imgproc.floodFill( mRgba, mask2, seed, newVal, rect, new Scalar( lo, lo, lo ), new Scalar( up, up, up), flags );

    // C++: 
    // mask = mask2( new Range( 1, mask2.rows() - 1 ), new Range( 1, mask2.cols() - 1 ) );
    mask = mask2.submat(new Range( 1, mask2.rows() - 1 ), new Range( 1, mask2.cols() - 1 ));

    mGray = histAndBackproj();
    bpUpdated = true;           

    return true;
}

  private Mat histAndBackproj() {
    Mat hist = new Mat();
    int h_bins = 30; 
    int s_bins = 32;

    // C++:
    //int histSize[] = { h_bins, s_bins };
    MatOfInt mHistSize = new MatOfInt (h_bins, s_bins);

    // C++:
    //float h_range[] = { 0, 179 };
    //float s_range[] = { 0, 255 };     
    //const float* ranges[] = { h_range, s_range };     
    //int channels[] = { 0, 1 };

    MatOfFloat mRanges = new MatOfFloat(0, 179, 0, 255);
    MatOfInt mChannels = new MatOfInt(0, 1);

    // C++:
    // calcHist( &hsv, 1, channels, mask, hist, 2, histSize, ranges, true, false );

    boolean accumulate = false;
    Imgproc.calcHist(Arrays.asList(mHSV), mChannels, mask, hist, mHistSize, mRanges, accumulate);

    // C++:
    // normalize( hist, hist, 0, 255, NORM_MINMAX, -1, Mat() );        
    Core.normalize(hist, hist, 0, 255, Core.NORM_MINMAX, -1, new Mat());

    // C++:
    // calcBackProject( &hsv, 1, channels, hist, backproj, ranges, 1, true );        
    Mat backproj = new Mat();
    Imgproc.calcBackProject(Arrays.asList(mHSV), mChannels, hist, backproj, mRanges, 1);

    return backproj;
}


/**
 * Method to scale screen coordinates to image coordinates, 
 * as they have different resolutions.
 * 
 * x - width; y - height; 
 * Nexus 4: xMax = 1196; yMax = 768
 * 
 * @param displayX
 * @param displayY
 * @return
 */
private Point getImageCoordinates(Mat image, float displayX, float displayY){
    Display display = getWindowManager().getDefaultDisplay();       
    android.graphics.Point outSize = new android.graphics.Point();
    display.getSize(outSize);

    float xScale = outSize.x / (float) image.width();
    float yScale = outSize.y / (float) image.height();                  

    return new Point(displayX/xScale, displayY/yScale);
}
http://stackoverflow.com/questions/17044147/back-projection-in-java-with-opencv

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:使用OpenCV在Java中反向投影