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.
- Implementación del efecto de pintura al óleo en android
- Detección de elipse con OpenCV
- No se puede importar javax.imageio.ImageIO en la aplicación de Android
- ¿Es posible cortar un mapa de bits a piezas pequeñas sin cargar toda la cosa en la memoria?
- Transmisión de cámara en vivo en Android
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; } }
- Cómo cambiar el color de fondo de mapa de bits a transparente y de fondo no debe arrastrar?
- Cómo convertir MatOfPoint a MatOfPoint2f en opencv java api
- Android - Cómo aplicar diffenernt Efectos de imagen en mapa de bits como sepia, blanco y negro, desenfoque, etc
- El parámetro setPictureSize de la cámara Android muestra una imagen con rayas
- Biblioteca de procesamiento de imágenes para Android?
- Filtro esférico en android
- No se puede construir caffe en android
- Umbral en Android con opencv
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.
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.
- No se pudo encontrar información del proveedor de 'ContentProvider'
- Disposición de Android: rellena el resto del espacio excepto