OpenCV-Based Media Java Swing Viewer
Let’s create an OpenCV-Based Media Viewer using Java‘s Swing framework (hereafter referred to as Swing).
Learn how to read and render media, including images (PNG, JPEG), videos (MP4, AVI), and webcam feeds, using the Java bindings of OpenCV, a well-known computer vision library. With this, you can use image files, video files such as MP4, and a webcam available on your computer.
1. Setting Up OpenCV and the IDE
Before we start developing the OpenCV-Based Media Viewer, you need to download the OpenCV SDK and Apache NetBeans. Java is also a prerequisite.
You can use the following download links:
- Apache NetBeans – You can download Apache NetBeans from its official website.
- OpenCV – You can get the latest version of OpenCV from its official GitHub repository
- Java – I will be using OpenJDK 17 or later, which I downloaded from the official website.
2. Design Concepts
I am going to discuss the concept of designing a OpenCV-Based Media Viewer using Swing.
Implementing a Swing application can be tedious and labor-intensive, so using an IDE can help save time. In my case, I will use Apache NetBeans for this task along with OpenJDK.
2.1 UI Layout
Let’s take a look at the concept of my UI layout design. Our OpenCV-Based Media Viewer is simple, featuring a ‘ComboBox’ for selection, a ‘Fire’ button for actions, and a screen to render media using Java Swing.
In the design above, an image and video selection combo box is positioned on the left side, with a “Fire” button located beneath it. You can select either “Image” or “Video” from the combo box, and a file chooser window will open immediately upon selection.
When the window is activated, you can choose files with specific extensions:
- Only JPEG, PNG, JPG, etc.
- Only MP4 or AVI files
by using the filtering function.
My original idea was to render the file based on its extension directly from the file dialog as soon as the user selected an item from the combo box on the Swing panel.
However, separating the steps—selection and execution—makes the process more convenient, so I decided to keep the “Fire” button for rendering.
Once pressed, the image or video file will be displayed on the main panel.

3. Implementing UI Layout
By utilizing the Swing components (Figure 1), our UI layout will consist of a main window as a JFrame
, along with other components such as a JPanel
, a JComboBox
, and a JButton
, for user actions in the NetBeans IDE.
3.1 Create Swing Project
Go to File -> New Project
In the “New Project” page of the wizard, I choose “Java with Ant” under Categories and “Java Application” under Projects, then click “Next” to continue with the default values.

In the “Name and Location” page of the wizard, make sure to fill in the fields: “Project Name”, “Project Location”, and uncheck “Create Main Class”. Then, click “Finish” to exit the wizard, and your project will be created.

3.2 Swing Components
In the NetBeans, you can create any of the Swing components using the Palette after project created.
Right-click on the “<default package>”, then select “New” and “JFrame Form” respectively in the ‘SwingViewer’ project we created.
new -> JFrame Form

In the “Name and Location” page of the wizard, make sure to fill in the fields: “Class Name” and “Package”. Then, click “Finish”, and now you will have a JFrame project.


Create a combo box and a button respectively as follows:

3.3 Capture ComboBox Event
It’s time to implement a listener interface to capture when the user’s combo box event occurs.
3.3.1 Create Event
In NetBeans IDE, to attach a listener, right-click on the component and open the properties dialog. Then, choose a handler from the Events tab.
I named the event jComboFileTypeChanged
.
The combo box items should be “None”, “Image”, and “Video”. Then, attach an event so that when the combo box selection changes, the jComboFileTypeChanged
method is triggered, receiving the user’s selection of either “Image” or “Video“.
3.3.2 Filtering files by extensions
The user identifies the specific file extension when the event is triggered and selects the correct file type based on whether the file is an “Image” or a “Video”.
A file chooser window will open, and:
- The user can select .jpg, .png, or .gif files when “Image” is selected, or
- The user can select .mp4 or .avi files when “Video” is selected,
with a filtering option.
The method described below ensures that the final result will be one of the following:
- an image file,
- a video file, or
- nothing (if the user cancels the selection).
We can easily select a file and its extension using the JFileChooser class in Swing
.


01 02 03 04 05 06 07 08 09 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 | private void jComboFileTypeChanged(java.awt.event.ItemEvent evt) { String itemName = evt.getItem().toString(); String initDir = "." ; File chooseFile = null ; int returnType = JFileChooser.FILES_ONLY; JFileChooser jFileChooser = null ; FileNameExtensionFilter extFilter = null ; String title = "choose " ; switch (itemName) { case "Image" : jFileChooser = new JFileChooser(initDir); extFilter = new FileNameExtensionFilter( "images" , "jpg" , "jpeg" , "png" ); jFileChooser.setFileFilter(extFilter); title += itemName; break ; case "Video" : jFileChooser = new JFileChooser(initDir); extFilter = new FileNameExtensionFilter( "videos" , "mp4" , "avi" ); jFileChooser.setFileFilter(extFilter); title += itemName; break ; default : //do nothing } returnType = jFileChooser.showDialog( this , title); switch (returnType) { case JFileChooser.APPROVE_OPTION: chooseFile = jFileChooser.getSelectedFile(); break ; case JFileChooser.CANCEL_OPTION: JOptionPane.showConfirmDialog( null , "Cancel by user" , title, JOptionPane.INFORMATION_MESSAGE); break ; default : //do nothing } } |
From the file dialog, we can get the path of the image file and pass it to the drawImage
method of OpenCVRenderPane
to render it. (We will cover this in the next section.)
Here is a code snippet demonstrating how to get a File
object from a file dialog:
01 02 03 04 05 06 07 08 09 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 | ... if (jFileChooser == null ) return ; returnType = jFileChooser.showDialog( this , title); switch (itemName) { case "Image" : switch (returnType) { case JFileChooser.APPROVE_OPTION: chooseFile = jFileChooser.getSelectedFile(); filePathTextField.setText(chooseFile.getAbsolutePath()); try { Mat fromMat = Imgcodecs.imread(chooseFile.getAbsolutePath()); BufferedImage chooseImage = toBufferedImage(fromMat); ((OpenCVRenderPane)openCVRenderPane).drawImage(chooseImage); } catch (IOException ie) { //error } break ; case JFileChooser.CANCEL_OPTION: JOptionPane.showConfirmDialog( null , "Canceled file selection by user" , title, JOptionPane.INFORMATION_MESSAGE); break ; default : //do nothing } break ; case "Video" : //do nothing break ; default : //do nothing } |
4. Swing Application : Steps to Render an image
Now, the OpenCV-Based Media Viewer uses the OpenCV library to read a user’s image from a file to render the JPanel
we are going to create.
We need three steps to render an image file within the Swing framework:
- Read the image file into a
Mat
object using the OpenCV library. - Convert the Mat object into a
BufferedImage
object. - Paint the
BufferedImage
object onto theJPanel
.
4.1 Reading an Image with OpenCV
We can use the imread
method to read an image from a file.
The signature of the imread
method, which returns a Mat
object, is as follows:
1 | public static Mat imread(String filename, int flags); |
We can’t render a Mat
object directly on Swing components after reading an image with the imread
method. The Mat
object cannot be interpreted by Swing, so we need to convert it to a BufferedImage
object.
The following two methods are used to convert a Mat
object to a BufferedImage
, and vice versa.
1 2 3 4 5 | public static BufferedImage toBufferedImage(Mat matrix) throws IOException { MatOfByte mob= new MatOfByte(); Imgcodecs.imencode( ".jpg" , matrix, mob); return ImageIO.read( new ByteArrayInputStream(mob.toArray())); } |
4.2 Rendering an image on a JPanel
We create a JPanel
object for rendering the BufferedImage
object from the conversion.
A Graphics
object must be used when rendering objects in Swing components. Therefore, we need to override the method as follows:
1 | protected void paintComponent(Graphics g); |
To use the paintComponent method:
- Create an object from the
JPanel
class. - Call the ‘repaint’ method whenever the
BufferedImage
is ready. - Render the object using the
Graphics
object (g).
4.3 Create a JPanel – OpenCVRenderPane
For simplicity, I first create an inner class named OpenCVRenderPane
, which inherits from the JPanel
class by overriding the paintComponent
method. (An inner class is a class defined within another class.)
The class is designed to accept a BufferedImage
object as an argument.
I referred to one of my answer on a Stack Overflow thread.
01 02 03 04 05 06 07 08 09 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 | import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import javax.swing.JFrame; import javax.swing.JPanel; … static final class OpenCVRenderPane extends JPanel { private static final long serialVersionUID = 1L; private BufferedImage imgBuffer; public OpenCVRenderPane() { } public OpenCVRenderPane( final BufferedImage imgBuffer) { this .imgBuffer = imgBuffer; } @Override public Dimension getPreferredSize() { return new Dimension( 240 , 220 ); } public void drawImage(BufferedImage img) { this .imgBuffer = img; repaint(); } @Override protected void paintComponent(Graphics g) { super .paintComponent(g); if (imgBuffer != null ) { Graphics2D g2d = (Graphics2D) g.create(); int x = (getWidth() - imgBuffer.getWidth()) / 2 ; int y = (getHeight() - imgBuffer.getHeight()) / 2 ; g2d.drawImage(imgBuffer, x, y, this ); g2d.dispose(); } } } |
We call the ‘repaint()’ method as soon as the ‘BufferedImage’ object is received as an argument in the ‘drawImage()’ method, which triggers the overridden ‘paintComponent()’ method immediately.
01 02 03 04 05 06 07 08 09 10 11 | public void drawImage(BufferedImage img) { this .imgBuffer = img; repaint(); } @Override protected void paintComponent(Graphics g) { super .paintComponent(g); ... } |
Move the buffered image object to the center of the panel :
1 2 3 4 5 6 7 | if (imgBuffer != null ) { Graphics2D g2d = (Graphics2D) g.create(); int x = (getWidth() - imgBuffer.getWidth()) / 2 ; int y = (getHeight() - imgBuffer.getHeight()) / 2 ; g2d.drawImage(imgBuffer, x, y, this ); g2d.dispose(); } |
4.4 Rendering Images
4.4.1 Declare and Initialize the Class
Let’s connect the drawing class created above to the GUI we built.
Applying this class will result in something like the following:
We will do the following:
Declare openCVRenderPane
as a JPanel
field:
1 | private javax.swing.JPanel openCVRenderPane; |
Then, instantiate it as an OpenCVRenderPane
object inside initComponents()
:
1 2 3 4 | private void initComponents() { openCVRenderPane = new OpenCVRenderPane(); // Other initialization code... } |
Finally we are ready for use the class.
4.4.2 Draw an image
We simply call the drawImage()
method of OpenCVRenderPane
after obtaining a Mat
object from the imread()
method and converting it to a BufferedImage
when the user selects ‘Image’ in the combo box.
We used the toBufferedImage
method to convert the Mat
object to a BufferedImage
.
For coding consistency, I used the imread
method to read an image, although we could also use the read
method from ImageIO
to convert an image file into a BufferedImage
object.
01 02 03 04 05 06 07 08 09 10 | try { Mat fromMat = Imgcodecs.imread(chooseFile.getAbsolutePath()); BufferedImage chooseImage = toBufferedImage(fromMat); //BufferedImage chooseImage = ImageIO.read(chooseFile); ((OpenCVRenderPane)openCVRenderPane).drawImage(chooseImage); } catch (IOException ie) { //error } |
5. Setting Up the OpenCV Library
Before using the OpenCV library in NetBeans IDE, we need to configure the environment variables.
There are two important steps to follow:
First, specify the file path of opencv.jar in the IDE. This file contains all the necessary classes to interface with OpenCV’s native functions.

Second, you need to set the actual OpenCV native library, as OpenCV is implemented in C++.
The library path must be set according to your operating system.
There are several ways to set the path, but in my case, I chose to specify the path using the JVM option (java.library.path
).

For example, if the installation directory of the OpenCV SDK is D:\DEV\WORK\Vision\opencv
, the java.library.path
should be set as follows :
1 | -Djava.library.path=D:\DEV\WORK\Vision\opencv\build\java\x64 |
You may encounter the following exception if the environment variables are not set properly.
01 02 03 04 05 06 07 08 09 10 | run: Exception in thread "AWT-EventQueue-0" java.lang.UnsatisfiedLinkError: no opencv_java4100 in java.library.path: D:\DEV\WORK\Vision\opencv\build\java\x64 at java.base /java .lang.ClassLoader.loadLibrary(ClassLoader.java:2429) at java.base /java .lang.Runtime.loadLibrary0(Runtime.java:818) at java.base /java .lang.System.loadLibrary(System.java:1989) at com.tobee.vision.opencv.JFrameOpenCV$OpenCVRenderPane.(JFrameOpenCV.java:250) at com.tobee.vision.opencv.JFrameOpenCV.initComponents(JFrameOpenCV.java:56) at com.tobee.vision.opencv.JFrameOpenCV.(JFrameOpenCV.java:41) at com.tobee.vision.opencv.JFrameOpenCV$3.run(JFrameOpenCV.java:455) at java.desktop /java .awt.event.InvocationEvent.dispatch(InvocationEvent.java:318) |
6. Checking the result
Once all these tasks are completed, we can find a useful but free image on Google and use it to test our implementation .
The displayed image looks fine. However, if the original image is larger than the panel, it may become distorted or cropped. To avoid this, the image should be scrollable.
Therefore, we will use the JScrollPane
class with the OpenCVRenderPane
class.

In the NetBeans IDE, we can accomplish this by:
- Setting the vertical and horizontal scrolling policies for the openCVScrollPane object so that it is always scrollable.
- Using the GUI Builder provided by NetBeans or modifying the code directly, as shown below.

And we need to override the getPreferredSize method to adjust the size of the received image buffer.
01 02 03 04 05 06 07 08 09 10 | @Override public Dimension getPreferredSize() { if (imgBuffer == null ) { return super .getPreferredSize(); } else { int w = imgBuffer.getWidth(); int h = imgBuffer.getHeight(); return new Dimension(w, h); } } |
The output is as followed:
In this post, we are focusing on a rendering test for displaying an image using the OpenCV library. Therefore, I won’t go into detail about how to use the NetBeans IDE to create and deploy components.
Please refer to the NetBeans website if you’re not familiar with it.
7. Displaying Videos in Swing
Using the OpenCV library, the Swing framework can read a video file in real-time and render it on the OpenCVRenderPane
once the user selects Video in the combo box.
- Choose the Video item from the combo box.
- Select a video file from the file dialog.
- The video will be displayed frame by frame on the panel.
That’s it.
7.1 A Few Design Changes
In the design below, I’ve added a text field to display the video file path, as I often forget the name of the file we select. This introduces a slight change to the design concept.
In the source code, we declare ‘filePathTextField’ as a ‘JTextField’.
1 | private javax.swing.JTextField filePathTextField; |
In the ‘jComboFileTypeChanged()’ method, we add the code to handle the event whenever it changes.
01 02 03 04 05 06 07 08 09 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 | private void jComboFileTypeChanged(java.awt.event.ItemEvent evt) { ... switch (itemName) { ... } if (jFileChooser == null ) return ; returnType = jFileChooser.showDialog( this , title); switch (itemName) { case "Image" : ... break ; case "Video" : switch (returnType) { case JFileChooser.APPROVE_OPTION: chooseFile = jFileChooser.getSelectedFile(); filePathTextField.setText(chooseFile.getAbsolutePath()); ... break ; case JFileChooser.CANCEL_OPTION: ... break ; default : //do nothing } break ; default : //do nothing } } |
The sample output:

7.2 Playing with Videos
To play a video or use a webcam, you should use OpenCV’s VideoCapture
class.
Here are the steps to make codes work:
a. Instantiate the default constructor:
1 | VideoCapture capture = new VideoCapture(); |
b. Open the video input from the filePath
:
1 | capture.open(filePath); |
c. Use the read
method to obtain a Mat
object from the video:
1 2 | Mat frame = new Mat(); capture.read(frame); |
d. Convert the Mat
object to a BufferedImage
.
Finally, you will be able to draw the converted BufferedImage
on the JPanel
.
7.3 Applying Video Rendering Events
Based on the code above, it is necessary to modify the OpenCVRenderPane
class to support videos in addition to images. Since the drawImage method is named to indicate it handles images, the method name needs to be updated.
The newly updated method is called onCVBufferReady
, and it takes two arguments.
1 | public void onCVBufferReady(File cvFile, int renderType); |
cvFile
: The file selected by the user.int renderType
: Specifies the type, either image or video.
The renderType must be one of the following:
OpenCVRenderPane.CV_NON_BUFFER
: Type not specified.OpenCVRenderPane.CV_IMG_BUFFER
: Image type.OpenCVRenderPane.CV_MOV_BUFFER
: Video type.
Let’s take a look at the implementation code:
01 02 03 04 05 06 07 08 09 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 | public void onCVBufferReady(File cvFile, int renderType) { mCVTypeNow = renderType; switch (mCVTypeNow) { case CV_IMG_BUFFER: { try { cvBuffer = ImageIO.read(cvFile); } catch (IOException ex) { Logger.getLogger(JFrameOpenCV. class .getName()).log(Level.SEVERE, null , ex); } } break ; case CV_MOV_BUFFER: { if (capture.isOpened()) { capture.release(); } capture.open(cvFile.getAbsolutePath()); isClose = false ; freamThread = new Thread(movRunner); freamThread.setDaemon( true ); freamThread.start(); } break ; } repaint(); } |
If a video is selected, it means CV_MOV_BUFFER is chosen.
If a video file is already open, close the current video stream first.
Then, reopen the user’s newly selected video file.
Finally, call movRunner
, which implements the Runnable interface.
7.4 movRunner class
This Runnable
class runs automatically when a video stream is opened.
Inside the while
loop below, the read method is used to obtain a Mat
object from the video, convert it to a BufferedImage
object, and then the repaint
method is called to immediately trigger the paintComponent
method.
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | private final Runnable movRunner = new Runnable() { @Override public void run() { while (!isClose) { if (!capture.isOpened()) return ; Mat cvFrame = new Mat(); if (capture.read(cvFrame)){ try { cvBuffer = toBufferedImage(cvFrame); } catch (IOException ex) { Logger.getLogger(JFrameOpenCV. class .getName()).log(Level.SEVERE, null , ex); } cvFrame.release(); } try { Thread.sleep( 50 ); } catch (InterruptedException ex) { Logger.getLogger(JFrameOpenCV. class .getName()).log(Level.SEVERE, null , ex); } repaint(); } } }; |
The ‘sleep’ method is used to prevent the video from playing too quickly.
Here’s what it looks like when running:

7.5 Small Design Changes
Let’s review a few changes:
- The
Fire
button’s functionality was unclear, so it was changed to aStop
button, allowing the video to be stopped when selected. ItemListener
was initially used to handle changes in the combo box, but it was difficult to manage, so it was replaced withActionListener
.- Now, when a video is selected, it stops whenever the combo box selection changes.
The updated design is as follows:

7.6 Change to the ActionListener interface
Attach the listener code as shown below:
1 2 3 4 5 6 7 8 9 | ComboCVFileType = new javax.swing.JComboBox(); ComboCVFileType.setModel( new javax.swing.DefaultComboBoxModel( new String[] { "None" , "Image" , "Video" })); ComboCVFileType.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { ComboCVFileTypeActionPerformed(evt); } }); |
In the “ComboCVFileTypeActionPerformed” method, check whether the event source is a combo box. If it is not, no action should be taken.
01 02 03 04 05 06 07 08 09 10 | ... JComboBox comboBox = null ; if ( evt.getSource() instanceof JComboBox) { comboBox = (JComboBox)evt.getSource(); } if (comboBox == null ) return ; ... |
It will be displayed like this:

8. Webcam
Finally, let’s explore how the webcam works in our OpenCV-based Media Viewer.
The control code for both videos and the webcam is exactly the same; the only difference is how the VideoCapture
class is used.
8.1 A Few Changes
Append the “Cam” item to the combo box as follows:

In NetBeans, you can add the Cam item in the Properties dialog.

8.2 Modify the OpenCVRenderPane class
To read the stream from the webcam, we can add an instance variable for the webcam.
First, declare the ID for the camera as follows:
1 | static final int CV_CAM_BUFFER = 3 ; |
When receiving the ID, you must modify the onCVBufferReady
method to switch the drawing mode to camera mode.
01 02 03 04 05 06 07 08 09 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 | public void onCVBufferReady(File cvFile, int renderType) { mCVTypeNow = renderType; switch (mCVTypeNow) { case CV_IMG_BUFFER: ... break ; case CV_MOV_BUFFER: ... break ; case CV_CAM_BUFFER: { System.out.println(CV_CAM_BUFFER); if (capture.isOpened()) { capture.release(); } capture.open( 0 ); cvFrame = new Mat(); isClose = false ; freamThread = new Thread(movRunner); freamThread.setDaemon( true ); freamThread.start(); } break ; } repaint(); } |
The open
method of the VideoCapture
class is the main difference between video and webcam, as shown below:
1 | capture.open( 0 ); |
The additional code is the same as that for the video.
8.3 Add Webcam Action
Now that the drawing for the webcam is complete, let’s add the code to select a camera from the combo box.
Add an action for the camera in the code as follows:
01 02 03 04 05 06 07 08 09 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 | private void ComboCVFileTypeActionPerformed(java.awt.event.ActionEvent evt) { JComboBox comboBox = null ; if ( evt.getSource() instanceof JComboBox) { comboBox = (JComboBox)evt.getSource(); } if (comboBox == null ) return ; String itemName = (String)comboBox.getSelectedItem(); ... switch (itemName) { case "Image" : ... break ; case "Mov" : ... break ; case "Cam" : ((OpenCVRenderPane)openCVRenderPane).onCVBufferReady(chooseFile, OpenCVRenderPane.CV_CAM_BUFFER); btnStopCVFrame.setActionCommand( "CAM_STOP" ); break ; case "None" : return ; default : //do nothing } ... } |
We don’t need to select a file for the webcam.
Additionally, a new CAM_STOP command has been created to distinguish it from the MOV_STOP command.

In the case of the webcam, a Restart
button may be needed in the near future.
9. Conclusion
Our OpenCV-based Media Viewer implements image, video, and camera display panels using Swing, a popular Java GUI framework.
OpenCV-based Media Viewer can serve as a foundation for exploring more advanced OpenCV features, such as image processing and object detection.
10. Download the Source Code
This was an example of Netbeans project files included.
You can download the full source code of this example here: OpenCV Swing Viewer Example