これまで,Java + OpenCVを使って,2枚の画像の特徴点検出(SRUFやSIFT)やWebカメラの画像表示をしてきました.
今回はそれを合わせて,Webカメラの画像を使って特徴点検出です.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
import org.opencv.core.Core; import org.opencv.core.Mat; import org.opencv.core.MatOfDMatch; import org.opencv.core.MatOfKeyPoint; import org.opencv.core.DMatch; import org.opencv.features2d.DescriptorExtractor; import org.opencv.features2d.DescriptorMatcher; import org.opencv.features2d.FeatureDetector; import org.opencv.features2d.Features2d; import org.opencv.imgcodecs.Imgcodecs; import org.opencv.imgproc.Imgproc; import java.awt.*; import java.awt.image.BufferedImage; import javax.swing.*; import org.opencv.core.Size; import org.opencv.videoio.VideoCapture; public class imagematch extends JPanel{ private static final long serialVersionUID = 1L; private BufferedImage image; // Create a constructor method public imagematch(){ super(); } private BufferedImage getimage(){ return image; } private void setimage(BufferedImage newimage){ image=newimage; return; } /** * Converts/writes a Mat into a BufferedImage. * * @param matrix Mat of type CV_8UC3 or CV_8UC1 * @return BufferedImage of type TYPE_3BYTE_BGR or TYPE_BYTE_GRAY */ public static BufferedImage matToBufferedImage(Mat matrix) { 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); switch (matrix.channels()) { case 1: type = BufferedImage.TYPE_BYTE_GRAY; break; case 3: type = BufferedImage.TYPE_3BYTE_BGR; // bgr to rgb 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; } public void paintComponent(Graphics g){ BufferedImage temp=getimage(); if(temp!=null){ g.drawImage(temp,10,10,temp.getWidth(),temp.getHeight(), this); } } public static void main(String[] args) { System.loadLibrary(Core.NATIVE_LIBRARY_NAME); JFrame frame = new JFrame("BasicPanel"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(1200,600); imagematch panel = new imagematch(); frame.setContentPane(panel); frame.setVisible(true); // 比較画像01 Mat image01 = Imgcodecs.imread("./resources/test01s.jpg"); // 比較画像02 Mat webcam_image=new Mat(); BufferedImage temp; VideoCapture capture =new VideoCapture(0); if( capture.isOpened()) { while( true ) { capture.read(webcam_image); if( !webcam_image.empty() ) { Mat image02 = webcam_image; Mat grayImage01 = new Mat(image01.rows(), image01.cols(), image01.type()); Imgproc.cvtColor(image01, grayImage01, Imgproc.COLOR_BGRA2GRAY); Core.normalize(grayImage01, grayImage01, 0, 255, Core.NORM_MINMAX); Mat grayImage02 = new Mat(image02.rows(), image02.cols(), image02.type()); Imgproc.cvtColor(image02, grayImage02, Imgproc.COLOR_BGRA2GRAY); Core.normalize(grayImage02, grayImage02, 0, 255, Core.NORM_MINMAX); // ------ SIFTの処理 ここから ------ FeatureDetector siftDetector = FeatureDetector.create(FeatureDetector.SIFT); DescriptorExtractor siftExtractor = DescriptorExtractor.create(DescriptorExtractor.SIFT); MatOfKeyPoint keyPoint01 = new MatOfKeyPoint(); siftDetector.detect(grayImage01, keyPoint01); MatOfKeyPoint keyPoint02 = new MatOfKeyPoint(); siftDetector.detect(grayImage02, keyPoint02); Mat descripters01 = new Mat(image01.rows(), image01.cols(), image01.type()); siftExtractor.compute(grayImage01, keyPoint01, descripters01); Mat descripters02 = new Mat(image02.rows(), image02.cols(), image02.type()); siftExtractor.compute(grayImage02, keyPoint02, descripters02); MatOfDMatch matchs = new MatOfDMatch(); DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE); matcher.match(descripters01, descripters02, matchs); // 上位50点以外の点を除去する int N = 50; DMatch[] tmp01 = matchs.toArray(); DMatch[] tmp02 = new DMatch[N]; for (int i=0; i<tmp02.length; i++) { tmp02[i] = tmp01[i]; } matchs.fromArray(tmp02); Mat matchedImage = new Mat(image01.rows(), image01.cols()*2, image01.type()); Features2d.drawMatches(image01, keyPoint01, image02, keyPoint02, matchs, matchedImage); // 出力画像 at SIFT //Imgcodecs.imwrite("./resources/descriptedImageBySIFT-" + now + ".jpg", matchedImage); BufferedImage matchedImage02 = matToBufferedImage(matchedImage); // ------ SIFTの処理 ここまで ------ // Webカメラ画像出力 Imgproc.resize(webcam_image, webcam_image, new Size(webcam_image.size().width*0.5,webcam_image.size().height*0.5)); frame.setSize(matchedImage.width()+300,matchedImage.height()+60); temp=matToBufferedImage(webcam_image); panel.setimage(matchedImage02); panel.repaint(); } else { System.out.println(" --(!) No captured frame -- "); } } } return; } } |
特徴点検出のプロトコルを変更したい場合は,113行目114行目のSIFTをその他のプロトコル(SURFやAKAZEなど)に変更してください.
結果
SIFT
SURF
AKAZE
動画からの検出になるとAKAZEのハイスピードが顕著でした.検出結果も比較もかなり正確だし,AKAZEいいですね.