Proyección posterior en Java con OpenCV

Quiero detectar características en una imagen con OpenCV usando retroproyección.

Para empezar, estaría muy feliz de computar un histograma de una sola imagen de un solo color y luego aplicarlo en una imagen más grande. Entonces puedo construir más en la parte superior de eso. Hay un ejemplo en C ++ y me gustaría hacer algo como esto en Java. Lamentablemente, la interfaz Java para OpenCV no está muy bien documentada.

A continuación se muestra el código que tengo hasta ahora, pero no funciona (obviamente, de lo contrario no pediría ayuda). Sería muy bueno si alguien pudiera ayudarme a conseguir que funcione o encontrar alguna buena documentación para la API de Java!

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; } } 

Varias cosas parecen extrañas en tu código, así que mi consejo para ti es seguir primero el tutorial de cerca y luego cambiarlo a tu caso de uso.

Parece que estás cerca del tutorial que estás siguiendo, pero parece que estás aplicando calcHist a una sola imagen de color. No veo cómo eso es útil, él debe ser típicamente una imagen de HSV con algún objeto (s) en lugar de otro. Además, le falta el paso de normalize .

Para ayudarle con eso he convertido ese Tutorial de la proyección posterior de C ++ a OpenCV4Android 2.4.8.

Aunque está utilizando Java en lugar de Android, la API es exactamente la misma, sólo la manipulación de entradas / salidas diferente variará.

El código original de C ++ se puede encontrar aquí.

Hizo algunos cambios muy pequeños en el tutorial original para hacerlo más utilizable para Android, por ejemplo:

  • Procesa la imagen de cámara en vivo, en lugar de imágenes estáticas;
  • Utiliza eventos táctiles para reemplazar el clic del ratón;
  • La salida de la retroproyección se muestra en la esquina superior izquierda que superpone la alimentación de la cámara;
  • Agregó el desenfoque gaussiano como reducción del ruido.

Back Projection Captura de pantalla

Todavía no he probado todos los pasos a fondo, pero el resultado final se ve bien.

Nota: tal como está, debe tocar la pantalla una vez para inicializar la proyección posterior …

Aquí está la mayor parte, lo que falta puede encontrar aquí en 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); } 

Utilice javaCV (una interfaz java para abrirCV). Utiliza la misma convención de método que openCV y tiene muchos ejemplos para trabajar con él.

  • ¿Cuál es la mejor manera de enviar una imagen desde un dispositivo Android a un servidor para su procesamiento y enviar los resultados?
  • Usando get () y put () para acceder a valores de píxeles en OpenCV para Java
  • Android - Cómo aplicar diffenernt Efectos de imagen en mapa de bits como sepia, blanco y negro, desenfoque, etc
  • Ajuste de saturación y ColorFilter a la imagen simultáneamente
  • Umbral adaptable rápido para Canny Edge Detector en Android
  • Detección de objetos android opencv
  • Utilizando el array de bytes de la cámara en bruto para la realidad aumentada
  • Android: Imagen sobre imagen
  • Cómo cambiar el color de fondo de mapa de bits a transparente y de fondo no debe arrastrar?
  • ¿Es posible cortar un mapa de bits a piezas pequeñas sin cargar toda la cosa en la memoria?
  • Implementación de diferentes modos PorterDuff en android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.