amp@java

            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            99 隨筆 :: 0 文章 :: 228 評論 :: 0 Trackbacks
          JMF太老了,各種問題得不到解決,Oracle也沒再升級過,如果能找到新東西,最好能把它扔掉。
          最近OpenCV比較火,還有人用Java封裝了OpenCV,成立了JavaCV項(xiàng)目,通過改造VideoInput這個(gè)基于C語言的項(xiàng)目,能夠用Java來調(diào)用攝像頭,JMF可以扔掉了。
          如果想測試,非常簡單,把那些編譯好的jar文件放入Build Path即可,如果是在Windows X86環(huán)境下,則只需要把帶Window和x86的包,以及不帶有任何平臺信息包放到Build Path即可。測試的程序可以用項(xiàng)目主頁上面那個(gè)Demo。代碼如下:

          import java.io.File;
          import java.net.URL;
          import org.bytedeco.javacv.*;
          import org.bytedeco.javacpp.*;
          import org.bytedeco.javacpp.indexer.*;
          import static org.bytedeco.javacpp.opencv_core.*;
          import static org.bytedeco.javacpp.opencv_imgproc.*;
          import static org.bytedeco.javacpp.opencv_calib3d.*;
          import static org.bytedeco.javacpp.opencv_objdetect.*;

          public class Demo {
              
          public static void main(String[] args) throws Exception {
                  String classifierName 
          = null;
                  
          if (args.length > 0) {
                      classifierName 
          = args[0];
                  } 
          else {
                      URL url 
          = new URL("https://raw.github.com/Itseez/opencv/2.4/data/haarcascades/haarcascade_frontalface_alt.xml");
                      File file 
          = Loader.extractResource(url, null"classifier"".xml");
                      file.deleteOnExit();
                      classifierName 
          = file.getAbsolutePath();
                  }

                  
          // Preload the opencv_objdetect module to work around a known bug.
                  Loader.load(opencv_objdetect.class);

                  
          // We can "cast" Pointer objects by instantiating a new object of the desired class.
                  CvHaarClassifierCascade classifier = new CvHaarClassifierCascade(cvLoad(classifierName));
                  
          if (classifier.isNull()) {
                      System.err.println(
          "Error loading classifier file \"" + classifierName + "\".");
                      System.exit(
          1);
                  }

                  
          // The available FrameGrabber classes include OpenCVFrameGrabber (opencv_highgui),
                  
          // DC1394FrameGrabber, FlyCaptureFrameGrabber, OpenKinectFrameGrabber,
                  
          // PS3EyeFrameGrabber, VideoInputFrameGrabber, and FFmpegFrameGrabber.
                  FrameGrabber grabber = FrameGrabber.createDefault(0);
                  grabber.start();

                  
          // FAQ about IplImage:
                  
          // - For custom raw processing of data, createBuffer() returns an NIO direct
                  
          //   buffer wrapped around the memory pointed by imageData, and under Android we can
                  
          //   also use that Buffer with Bitmap.copyPixelsFromBuffer() and copyPixelsToBuffer().
                  
          // - To get a BufferedImage from an IplImage, we may call getBufferedImage().
                  
          // - The createFrom() factory method can construct an IplImage from a BufferedImage.
                  
          // - There are also a few copy*() methods for BufferedImage<->IplImage data transfers.
                  IplImage grabbedImage = grabber.grab();
                  
          int width  = grabbedImage.width();
                  
          int height = grabbedImage.height();
                  IplImage grayImage    
          = IplImage.create(width, height, IPL_DEPTH_8U, 1);
                  IplImage rotatedImage 
          = grabbedImage.clone();

                  
          // Objects allocated with a create*() or clone() factory method are automatically released
                  
          // by the garbage collector, but may still be explicitly released by calling release().
                  
          // You shall NOT call cvReleaseImage(), cvReleaseMemStorage(), etc. on objects allocated this way.
                  CvMemStorage storage = CvMemStorage.create();

                  
          // The OpenCVFrameRecorder class simply uses the CvVideoWriter of opencv_highgui,
                  
          // but FFmpegFrameRecorder also exists as a more versatile alternative.
                  FrameRecorder recorder = FrameRecorder.createDefault("output.avi", width, height);
                  recorder.start();

                  
          // CanvasFrame is a JFrame containing a Canvas component, which is hardware accelerated.
                  
          // It can also switch into full-screen mode when called with a screenNumber.
                  
          // We should also specify the relative monitor/camera response for proper gamma correction.
                  CanvasFrame frame = new CanvasFrame("Some Title", CanvasFrame.getDefaultGamma()/grabber.getGamma());

                  
          // Let's create some random 3D rotation
                  CvMat randomR = CvMat.create(33), randomAxis = CvMat.create(31);
                  
          // We can easily and efficiently access the elements of matrices and images
                  
          // through an Indexer object with the set of get() and put() methods.
                  DoubleIndexer Ridx = randomR.createIndexer(), axisIdx = randomAxis.createIndexer();
                  axisIdx.put(
          0, (Math.random()-0.5)/4, (Math.random()-0.5)/4, (Math.random()-0.5)/4);
                  cvRodrigues2(randomAxis, randomR, 
          null);
                  
          double f = (width + height)/2.0;  Ridx.put(02, Ridx.get(02)*f);
                                                    Ridx.put(
          12, Ridx.get(12)*f);
                  Ridx.put(
          20, Ridx.get(20)/f); Ridx.put(21, Ridx.get(21)/f);
                  System.out.println(Ridx);

                  
          // We can allocate native arrays using constructors taking an integer as argument.
                  CvPoint hatPoints = new CvPoint(3);

                  
          while (frame.isVisible() && (grabbedImage = grabber.grab()) != null) {
                      cvClearMemStorage(storage);

                      
          // Let's try to detect some faces! but we need a grayscale image
                      cvCvtColor(grabbedImage, grayImage, CV_BGR2GRAY);
                      CvSeq faces 
          = cvHaarDetectObjects(grayImage, classifier, storage,
                              
          1.13, CV_HAAR_DO_CANNY_PRUNING);
                      
          int total = faces.total();
                      
          for (int i = 0; i < total; i++) {
                          CvRect r 
          = new CvRect(cvGetSeqElem(faces, i));
                          
          int x = r.x(), y = r.y(), w = r.width(), h = r.height();
                          cvRectangle(grabbedImage, cvPoint(x, y), cvPoint(x
          +w, y+h), CvScalar.RED, 1, CV_AA, 0);

                          
          // To access or pass as argument the elements of a native array, call position() before.
                          hatPoints.position(0).x(x-w/10)   .y(y-h/10);
                          hatPoints.position(
          1).x(x+w*11/10).y(y-h/10);
                          hatPoints.position(
          2).x(x+w/2)    .y(y-h/2);
                          cvFillConvexPoly(grabbedImage, hatPoints.position(
          0), 3, CvScalar.GREEN, CV_AA, 0);
                      }

                      
          // Let's find some contours! but first some thresholding
                      cvThreshold(grayImage, grayImage, 64255, CV_THRESH_BINARY);

                      
          // To check if an output argument is null we may call either isNull() or equals(null).
                      CvSeq contour = new CvSeq(null);
                      cvFindContours(grayImage, storage, contour, Loader.sizeof(CvContour.
          class),
                              CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
                      
          while (contour != null && !contour.isNull()) {
                          
          if (contour.elem_size() > 0) {
                              CvSeq points 
          = cvApproxPoly(contour, Loader.sizeof(CvContour.class),
                                      storage, CV_POLY_APPROX_DP, cvContourPerimeter(contour)
          *0.020);
                              cvDrawContours(grabbedImage, points, CvScalar.BLUE, CvScalar.BLUE, 
          -11, CV_AA);
                          }
                          contour 
          = contour.h_next();
                      }

                      cvWarpPerspective(grabbedImage, rotatedImage, randomR);

                      frame.showImage(rotatedImage);
                      recorder.record(rotatedImage);
                  }
                  frame.dispose();
                  recorder.stop();
                  grabber.stop();
              }
          }

          不過這個(gè)代碼包含了人臉識別,而人臉識別需要下載一個(gè)xml文件來定義識別的模式,代碼中那個(gè)xml鏈接下載下來的xml文件是會解析出錯(cuò)的,可能是那個(gè)版本比較新,JavaCV還沒跟上,所以解析不了。經(jīng)過搜索,發(fā)現(xiàn)有人提供了一個(gè)老版本的xml文件,能夠順利解析,會在視頻中把人臉用綠框框住。
          所以,把代碼中的
          URL url = new URL("https://raw.github.com/Itseez/opencv/2.4/data/haarcascades/haarcascade_frontalface_alt.xml");
          改為
          URL url = new URL("https://raw.githubusercontent.com/Danukeru/FOUCAM/master/haarcascade_frontalface.xml");
          即可順利運(yùn)行。
          運(yùn)行后發(fā)現(xiàn)很多線條和框框,畫面也是斜的,如下圖所示:


          這是用來演示JavaCV對圖像的處理,如果對這些沒有興趣,可以簡單地用以下代碼來顯示攝像頭的圖像:

          import org.bytedeco.javacpp.opencv_core.IplImage;
          import org.bytedeco.javacv.CanvasFrame;
          import org.bytedeco.javacv.FrameGrabber;

          public class Demo3 {
              
          public static void main(String[] args) throws Exception {


                  
          // The available FrameGrabber classes include OpenCVFrameGrabber (opencv_highgui),
                  
          // DC1394FrameGrabber, FlyCaptureFrameGrabber, OpenKinectFrameGrabber,
                  
          // PS3EyeFrameGrabber, VideoInputFrameGrabber, and FFmpegFrameGrabber.
                  FrameGrabber grabber = FrameGrabber.createDefault(1);
                  grabber.start();

                  
          // FAQ about IplImage:
                  
          // - For custom raw processing of data, createBuffer() returns an NIO direct
                  
          //   buffer wrapped around the memory pointed by imageData, and under Android we can
                  
          //   also use that Buffer with Bitmap.copyPixelsFromBuffer() and copyPixelsToBuffer().
                  
          // - To get a BufferedImage from an IplImage, we may call getBufferedImage().
                  
          // - The createFrom() factory method can construct an IplImage from a BufferedImage.
                  
          // - There are also a few copy*() methods for BufferedImage<->IplImage data transfers.
                  IplImage grabbedImage = grabber.grab();
                  CanvasFrame frame 
          = new CanvasFrame("Some Title", CanvasFrame.getDefaultGamma()/grabber.getGamma());

                  
          while (frame.isVisible() && (grabbedImage = grabber.grab()) != null) {


                      frame.showImage(grabbedImage);
                      
                  }
                  frame.dispose();
                  
                  grabber.stop();
              }
          }

          如下圖所示:


          當(dāng)然,這樣只是把攝像頭的圖像顯示出來,沒有任何用處,所以如果你想要處理其中的圖像,就需要增加代碼。例如,如果你需要截取攝像頭的圖像做進(jìn)一步處理,就可以通過IplImage的getBufferedImage()方法來得到BufferedImage,然后再處理這個(gè)BufferedImage,例如解析二維碼。

          不過,JavaCV默認(rèn)是把圖像顯示在一個(gè)CanvasFrame對象中,這個(gè)對象繼承了JFrame,所以只能用作頂層窗口,不能嵌入到其他窗口中。為了能夠把它嵌入到其他窗口,可以修改一下代碼,繼承一個(gè)Canvas對象:
          public class ImageCanvas extends Canvas {
                  
              
          private BufferedImage img;
              
              @Override 
          public void update(Graphics g) {
                  paint(g);
              }
              
              @Override 
          public void paint(Graphics g) {
                  
                  
          // Calling BufferStrategy.show() here sometimes throws
                  
          // NullPointerException or IllegalStateException,
                  
          // but otherwise seems to work fine.
                  try {
                      
          if (getWidth() <= 0 || getHeight() <= 0) {
                          
          return;
                      }
                      BufferStrategy strategy 
          = getBufferStrategy();
                      
          do {
                          
          do {
                              g 
          = strategy.getDrawGraphics();
                              
          if (img != null) {                        
                                  g.drawImage(img, 
          00, getWidth(), getHeight(), null);
                              }
                              g.dispose();
                          } 
          while (strategy.contentsRestored());
                          strategy.show();
                      } 
          while (strategy.contentsLost());
                  } 
          catch (NullPointerException e) {
                  } 
          catch (IllegalStateException e) { }
              }

              
              
          public BufferedImage getImg() {
                  
          return img;
              }

              
          public void setImg(BufferedImage img) {
                  
          this.img = img;        
                  repaint();                       
              }


              
          public void init(){
                  
          new Thread(){
                      
          public void run(){
                          
          boolean error = true;
                          
          while(error){
                              
          try{
                                  error 
          = false;
                                  createBufferStrategy(
          2);
                              }
          catch(IllegalStateException e){
                                  error 
          = true;
                                  
          try {
                                      Thread.sleep(
          100);
                                  } 
          catch (InterruptedException e1) {
                                      
          // TODO Auto-generated catch block
                                      e1.printStackTrace();
                                  }
                              }
                          }
                      }
                  }.start();
              }
          使用的時(shí)候就把這個(gè)ImageCanvas當(dāng)作普通的控件加入到窗口中,然后調(diào)用init()函數(shù)即可。init函數(shù)的作用是在控件顯示出來后才調(diào)用createBufferStrategy(2)語句,否則會拋出IllegalStateException異常。
          這個(gè)ImageCanvas使用了雙緩沖機(jī)制來顯示視頻(實(shí)際上是不間斷地顯示圖像),避免圖像閃爍。在此之前,嘗試了網(wǎng)上找到的雙緩沖代碼,效果都不理想,只有這個(gè)能夠不閃爍。
          不過用了這個(gè)控件來顯示視頻,就不能全屏了。
          加入控件后,顯示圖像只需要調(diào)用
          setImg(BufferedImage img)函數(shù)即可。也就是把
          frame.showImage(grabbedImage);
          改為
          canvas.setImg(grabbedImage.getBufferedImage());


          posted on 2015-02-15 11:41 amp@java 閱讀(10433) 評論(7)  編輯  收藏 所屬分類: Java common

          評論

          # re: 用JavaVC替換JMF連接攝像頭 2015-02-16 14:38 京山游俠
          牛。  回復(fù)  更多評論
            

          # re: 用JavaVC替換JMF連接攝像頭 2015-03-06 23:50 gaochang
          看標(biāo)題似乎很強(qiáng)大,可是怎么,好像,應(yīng)該會有點(diǎn)用吧  回復(fù)  更多評論
            

          # re: 用JavaVC替換JMF連接攝像頭 2015-03-08 13:39 marchalex
          贊一個(gè)。
          mark一記。回去研究:)  回復(fù)  更多評論
            

          # re: 用JavaVC替換JMF連接攝像頭 2015-10-19 20:28 cruiser
          IplImage grabbedImage = grabber.grab();這一句報(bào)錯(cuò)  回復(fù)  更多評論
            

          # re: 用JavaVC替換JMF連接攝像頭 2015-11-13 19:40 ytuio21
          @cruiser
          你使用的是新版本的javacv吧,要這樣獲得IpImage: OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
          IplImage frame = converter.convert(grabber.grab());  回復(fù)  更多評論
            

          # re: 用JavaVC替換JMF連接攝像頭 2015-11-19 17:49 clyao
          @ytuio21
          最后一點(diǎn)不太明白,有完整的代碼可以參考一下不?  回復(fù)  更多評論
            

          # re: 用JavaVC替換JMF連接攝像頭 2016-01-07 17:35 ll
          @clyao
          你找到使用方法了嗎兄弟  回復(fù)  更多評論
            

          主站蜘蛛池模板: 鹤山市| 政和县| 建水县| 安仁县| 德安县| 揭阳市| 遵义市| 西丰县| 鸡西市| 唐海县| 兴城市| 遂昌县| 布尔津县| 吉木萨尔县| 三门县| 廊坊市| 青海省| 德江县| 龙江县| 璧山县| 武乡县| 惠水县| 诸城市| 克什克腾旗| 体育| 阳谷县| 桑日县| 蒲城县| 三都| 邯郸县| 安图县| 沛县| 绥芬河市| 吉隆县| 盐津县| 高州市| 祁门县| 安平县| 佛坪县| 潜江市| 靖宇县|