OpenCV Renk Tespiti Obje Takibi
Bu projede kamera aygıtından alınan görüntü üzerinde belirlediğimiz bazı renkleri tespit edecek ve bu renge sahip objeleri işaretleyeceğiz. Öncelikle bir renk aralığı belirleyeceğiz daha sonra kamera aygıtından yakalanan RGB renk uzayına sahip görüntüyü HSV renk uzayına çevireceğiz. Görüntü üzerinde eşikleme, aşındırma ve genişletme operatörlerini uygulayacağız. Kenar bulma gibi metotları kullanarak renklerin ayrımını tespit edip nesneleri işaretleyeceğiz.
Renk tespiti için HSV uzayını kullanacağız, RGB renk uzayında yapılacak olan threshold HSV renk uzayında yapılacak threshold a göre yetersizdir. HSV de H (HUE) değeri daha ayırt edilebilir şekilde değiştiği için farklı renkli objelerin resimde tespiti çok daha kolay olmaktadır. HSV uzaydaki renk kodları aralığını aşağıdaki görselden tespit edebilirsiniz. Proje 2 adet sınıftan oluşacak, birincisi Frame’ler ve görüntülenecek olan kamera görüntüsünü yönetecek sınıf, diğer ise renk tespitini ve işaretleme gibi işlemleri yerine getirecek sınıf.
import java.awt.Graphics; import java.awt.image.BufferedImage; import javax.swing.JPanel; import org.opencv.core.Mat; //Kameradan alınan ve işlenen görüntüler jpanel üzerinde görüntülenecek class Panel extends JPanel { private static final long serialVersionUID = 1L; private BufferedImage image; public Panel() { super(); } private BufferedImage getimage() { return image; } public void setimage(BufferedImage newimage) { image = newimage; return; } public void setimagewithMat(Mat newimage) { image = this.ConvertImage(newimage); return; } /* Mat nesnesini frame içerisinde göstermek için BufferedImage tipine çeviriyoruz*/ public BufferedImage ConvertImage(Mat matrix) { // Mat nesnesinin sütun, satır ve boyutunu BufferedImage nesnesi içintutuyoruz int cols = matrix.cols(); int rows = matrix.rows(); int elemSize = (int) matrix.elemSize(); byte[] data = new byte[cols * rows * elemSize]; int type; matrix.get(0, 0, data); // Mat nesnesinin kaç kanallı, hangi renk uzayında olduğunu tespit ediyoruz. switch (matrix.channels()) { // Tek kanallı gri renk uzayına sahip matris case 1: type = BufferedImage.TYPE_BYTE_GRAY; break; // Üç kanallı BGR renk uzayına sahip matris case 3: type = BufferedImage.TYPE_3BYTE_BGR; /* * Opencv rgb renk uzayını bgr olarak tuttuğu için görüntülemede * düzgün bir görüntü elde etmek amacıyla rgb uzayına çeviriyoruz */ byte b; for (int i = 0; i<data.length; i = i + 3) { b = data[i]; data[i] = data[i + 2]; data[i + 2] = b; } break; default: return null; } BufferedImage image2 = new BufferedImage(cols, rows, type); image2.getRaster().setDataElements(0, 0, cols, rows, data); return image2; } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); BufferedImage temp = getimage(); if (temp != null) g.drawImage(temp, 10, 10, temp.getWidth(), temp.getHeight(), this); } }
Renk tespitini yapacak olan ikinci sınıf.
import java.util.ArrayList; import java.util.List; import javax.swing.JFrame; import javax.swing.JOptionPane; import org.opencv.core.Core; import org.opencv.core.CvType; import org.opencv.core.Mat; import org.opencv.core.MatOfPoint; import org.opencv.core.Scalar; import org.opencv.core.Size; import org.opencv.imgproc.Imgproc; import org.opencv.videoio.VideoCapture; public class Detector { public static void main(String arg[]) { System.loadLibrary(Core.NATIVE_LIBRARY_NAME); // Anlıkolarakyakalanankameragörüntülerinigöstereceğimiz frame ve panel JFrame cameraFrame = new JFrame("Anlık kamera görüntüsü"); cameraFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cameraFrame.setSize(640, 480); cameraFrame.setBounds(0, 0, cameraFrame.getWidth(), cameraFrame.getHeight()); Panel panelCamera = new Panel(); cameraFrame.setContentPane(panelCamera); cameraFrame.setVisible(true); // İşlenecekgörüntünün threshold uygulandıktan sonraki halini // göstereceğimiz frame ve panel JFrame thresholdFrame = new JFrame("Threshold görüntü"); thresholdFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); thresholdFrame.setSize(640, 480); thresholdFrame.setBounds(0, 0, cameraFrame.getWidth(), cameraFrame.getHeight()); Panel panelThreshold = new Panel(); thresholdFrame.setContentPane(panelThreshold); thresholdFrame.setVisible(true); // Video akışıiçin, 0 ilevarsayılankamerayıbaşlatacağız VideoCapture capture = new VideoCapture(0); // Parametreleri atıyoruz /*capture.set(3, 1366); capture.set(4, 768); capture.set(15, -2);*/ // Saf kameragörünrüsü Mat webcam_image = new Mat(); // Hsv renk uzayında görüntüsü Mat hsv_image = new Mat(); // 1. ve 2. threshold Mat thresholded = new Mat(); Mat thresholded2 = new Mat(); // Kameradan görüntü oku capture.read(webcam_image); // Kameradan alınan görüntüleri gösterecek olduğumuz frame boyutları // kameradan okunang örüntüye göre ayarlanıyor. cameraFrame.setSize(webcam_image.width() + 50, webcam_image.height() + 50); thresholdFrame.setSize(webcam_image.width() + 50, webcam_image.height() + 50); Mat array255 = new Mat(webcam_image.height(), webcam_image.width(), CvType.CV_8UC1); array255.setTo(new Scalar(255)); Mat distance = new Mat(webcam_image.height(), webcam_image.width(), CvType.CV_8UC1); List<Mat> lhsv = new ArrayList<Mat>(3); Mat circles = new Mat(); // Renktespitiburadabelirttiğimizminve max değerleregöreyapılacak // hsvuzayındaverdiğimizrenktonlarıarasındaki her renktespitedilecektir. // Renkaralıklarıiçinhsvrenktablolarınagözatabilirsiniz. Scalar minColor = new Scalar(5, 100, 100, 0); Scalar maxColor = new Scalar(10, 255, 255, 0); // Kamera aygıtı çalışıyor ise if (capture.isOpened()) { while (true) { capture.read(webcam_image); // Bir görüntü okunmuş ve boşdeğilse if (!webcam_image.empty()) { // Kameradan okunan görüntü hsv renk uzayına dönüştürülür Imgproc.cvtColor(webcam_image, hsv_image, Imgproc.COLOR_BGR2HSV); Core.inRange(hsv_image, minColor, maxColor, thresholded); // Erode ve dilate işlemi uygulanır yapısal element ölçüleri // iki işlemdede aynıdır Imgproc.erode(thresholded, thresholded, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(8, 8))); Imgproc.dilate(thresholded, thresholded, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(8, 8))); /* * Split metodu * ilegörüntüüzerindekihistogramlarıparçalıyoruz. Matrisin * her boyutu ayrı ayrı nesnelere atanıyor. */ Core.split(hsv_image, lhsv); Mat S = lhsv.get(1); Mat V = lhsv.get(2); // dizilerarası element farklarıhesaplıyoruz Core.subtract(array255, S, S); Core.subtract(array255, V, V); S.convertTo(S, CvType.CV_32F); V.convertTo(V, CvType.CV_32F); // 2 boyutluvektörlerimizinbüyüklüğünühesaplıyoruz Core.magnitude(S, V, distance); /* * Verilendeğerlerarasında thresholding uyguluyor. * pikselindeğeriverilendeğerlerarasındaise o * piksel,beyazdeğilsesiyahyapılıyor. */ Core.inRange(distance, new Scalar(0.0), new Scalar(200.0), thresholded2); Core.bitwise_and(thresholded, thresholded2, thresholded); // thresholded içingaussian blur filtresiuyguluyoruz Imgproc.GaussianBlur(thresholded, thresholded, new Size(9, 9), 0, 0); // Şeklindışhatları List<MatOfPoint> contours = new ArrayList<MatOfPoint>(); Imgproc.HoughCircles(thresholded, circles, Imgproc.CV_HOUGH_GRADIENT, 2, thresholded.height() / 8, 200, 100, 0, 0); // thresholding sonrasınesnenin binary // haliüzerindebağlınoktalarıtesiğediyoruz Imgproc.findContours(thresholded, contours, thresholded2, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE); // Nesneninkonumunaaşağıdakirenkileçiziyoruz Imgproc.drawContours(webcam_image, contours, -2, new Scalar(10, 0, 0), 4); /* * Panellerüzerinegörünrüleriatayıp frame'lerin * tekrardançizilmesinisağlıyoruz */ panelCamera.setimagewithMat(webcam_image); panelThreshold.setimagewithMat(thresholded); cameraFrame.repaint(); thresholdFrame.repaint(); } else { JOptionPane.showMessageDialog(null, "Kamera aygıtına bağlanılamadı!"); break; } } } } }