在您的代码中,有些事情看起来很奇怪,所以我对您的建议是,首先紧跟本教程,然后将其更改为您的用例。
您似乎在某种程度上接近您正在遵循的教程,但看起来您正在将calcHist
应用于单个彩色图像。我看不出这有什么用,它通常应该是带有某些对象的HSV图像。此外,您缺少normalize
步骤。
为了帮助您,我将C ++反向投影教程转换为OpenCV4Android 2.4.8。
尽管您使用Java而不是Android,但API完全相同,只是样板输入/输出处理会有所不同。
对原始教程进行了一些非常小的更改,以使其更适用于Android,例如:
- 它处理实时摄像机图像,而不是静态图像;
- 使用触摸事件代替鼠标单击;
- 反投影的输出显示在与摄像机源重叠的左上角;
- 添加了高斯模糊作为降噪功能。
我尚未彻底测试所有步骤,但最终结果还可以。
注意:就目前而言,您需要触摸屏幕一次以初始化Back Projection ...
这是大部分内容,缺少的内容可以在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);
}
0
我想使用反投影在OpenCV中检测图像中的特征。
首先,我将很高兴计算单个彩色小图像的直方图,然后将其应用于较大的图像。然后,我可以在此基础上进一步构建。 C ++中有一个示例,我想在Java中做类似的事情。遗憾的是,OpenCV的Java接口没有很好的文档说明。
下面是我到目前为止拥有的代码,但是它无法正常工作(显然,否则我不会寻求帮助)。如果有人可以帮助我使它正常工作或找到一些有关Java API的很好的文档 ,那将非常好 !