Skip to content

Commit 6512a4b

Browse files
committed
OpenCV Java Highgui Class
The objective is to: *Reduce greatly the number of lines of code in the Java codes; *Make it easy for Java users to add a trackbar and show the results; *Get the code more similar between C++, Java and Python, making the tutorials more uniform.
1 parent e5aa213 commit 6512a4b

File tree

3 files changed

+330
-1
lines changed

3 files changed

+330
-1
lines changed

modules/highgui/CMakeLists.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
set(the_description "High-level GUI")
2-
ocv_add_module(highgui opencv_imgproc opencv_imgcodecs OPTIONAL opencv_videoio WRAP python)
2+
if(ANDROID)
3+
ocv_add_module(highgui opencv_imgproc opencv_imgcodecs OPTIONAL opencv_videoio WRAP python)
4+
else()
5+
ocv_add_module(highgui opencv_imgproc opencv_imgcodecs OPTIONAL opencv_videoio WRAP python java)
6+
endif()
37

48
# ----------------------------------------------------------------------------
59
# CMake file for highgui. See root CMakeLists.txt
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
package org.opencv.highgui;
2+
3+
import org.opencv.core.Mat;
4+
5+
import javax.swing.*;
6+
import java.awt.*;
7+
import java.awt.event.KeyEvent;
8+
import java.awt.event.KeyListener;
9+
import java.awt.image.BufferedImage;
10+
import java.awt.image.DataBufferByte;
11+
import java.util.HashMap;
12+
import java.util.Iterator;
13+
import java.util.Map;
14+
import java.util.concurrent.CountDownLatch;
15+
import java.util.concurrent.TimeUnit;
16+
17+
/**
18+
* This class was designed for use in Java applications
19+
* to recreate the OpenCV HighGui functionalities.
20+
*/
21+
public final class HighGui {
22+
23+
// Constants for namedWindow
24+
public final static int WINDOW_NORMAL = ImageWindow.WINDOW_NORMAL;
25+
public final static int WINDOW_AUTOSIZE = ImageWindow.WINDOW_AUTOSIZE;
26+
27+
// Control Variables
28+
public static int n_closed_windows = 0;
29+
public static int pressedKey = -1;
30+
public static CountDownLatch latch = new CountDownLatch(1);
31+
32+
// Windows Map
33+
public static Map<String, ImageWindow> windows = new HashMap<String, ImageWindow>();
34+
35+
public static void namedWindow(String winname) {
36+
namedWindow(winname, HighGui.WINDOW_AUTOSIZE);
37+
}
38+
39+
public static void namedWindow(String winname, int flag) {
40+
ImageWindow newWin = new ImageWindow(winname, flag);
41+
if (windows.get(winname) == null) windows.put(winname, newWin);
42+
}
43+
44+
public static void imshow(String winname, Mat img) {
45+
if (img.empty()) {
46+
System.err.println("Error: Empty image in imshow");
47+
System.exit(-1);
48+
} else {
49+
ImageWindow tmpWindow = windows.get(winname);
50+
if (tmpWindow == null) {
51+
ImageWindow newWin = new ImageWindow(winname, img);
52+
windows.put(winname, newWin);
53+
} else {
54+
tmpWindow.setMat(img);
55+
}
56+
}
57+
}
58+
59+
public static Image toBufferedImage(Mat m) {
60+
int type = BufferedImage.TYPE_BYTE_GRAY;
61+
62+
if (m.channels() > 1) {
63+
type = BufferedImage.TYPE_3BYTE_BGR;
64+
}
65+
66+
int bufferSize = m.channels() * m.cols() * m.rows();
67+
byte[] b = new byte[bufferSize];
68+
m.get(0, 0, b); // get all the pixels
69+
BufferedImage image = new BufferedImage(m.cols(), m.rows(), type);
70+
71+
final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
72+
System.arraycopy(b, 0, targetPixels, 0, b.length);
73+
74+
return image;
75+
}
76+
77+
public static JFrame createJFrame(String title, int flag) {
78+
JFrame frame = new JFrame(title);
79+
80+
frame.addWindowListener(new java.awt.event.WindowAdapter() {
81+
@Override
82+
public void windowClosing(java.awt.event.WindowEvent windowEvent) {
83+
n_closed_windows++;
84+
if (n_closed_windows == windows.size()) latch.countDown();
85+
}
86+
});
87+
88+
frame.addKeyListener(new KeyListener() {
89+
@Override
90+
public void keyTyped(KeyEvent e) {
91+
}
92+
93+
@Override
94+
public void keyReleased(KeyEvent e) {
95+
}
96+
97+
@Override
98+
public void keyPressed(KeyEvent e) {
99+
pressedKey = e.getKeyCode();
100+
latch.countDown();
101+
}
102+
});
103+
104+
if (flag == WINDOW_AUTOSIZE) frame.setResizable(false);
105+
106+
return frame;
107+
}
108+
109+
public static void waitKey(){
110+
waitKey(0);
111+
}
112+
113+
public static int waitKey(int delay) {
114+
// Reset control values
115+
latch = new CountDownLatch(1);
116+
n_closed_windows = 0;
117+
pressedKey = -1;
118+
119+
// If there are no windows to be shown return
120+
if (windows.isEmpty()) {
121+
System.err.println("Error: waitKey must be used after an imshow");
122+
System.exit(-1);
123+
}
124+
125+
// Remove the unused windows
126+
Iterator<Map.Entry<String,
127+
ImageWindow>> iter = windows.entrySet().iterator();
128+
while (iter.hasNext()) {
129+
Map.Entry<String,
130+
ImageWindow> entry = iter.next();
131+
ImageWindow win = entry.getValue();
132+
if (win.alreadyUsed) {
133+
iter.remove();
134+
win.frame.dispose();
135+
}
136+
}
137+
138+
// (if) Create (else) Update frame
139+
for (ImageWindow win : windows.values()) {
140+
141+
if (win.img != null) {
142+
143+
ImageIcon icon = new ImageIcon(toBufferedImage(win.img));
144+
145+
if (win.lbl == null) {
146+
JFrame frame = createJFrame(win.name, win.flag);
147+
JLabel lbl = new JLabel(icon);
148+
win.setFrameLabelVisible(frame, lbl);
149+
} else {
150+
win.lbl.setIcon(icon);
151+
}
152+
} else {
153+
System.err.println("Error: no imshow associated with" + " namedWindow: \"" + win.name + "\"");
154+
System.exit(-1);
155+
}
156+
}
157+
158+
try {
159+
if (delay == 0) {
160+
latch.await();
161+
} else {
162+
latch.await(delay, TimeUnit.MILLISECONDS);
163+
}
164+
} catch (InterruptedException e) {
165+
e.printStackTrace();
166+
}
167+
168+
// Set all windows as already used
169+
for (ImageWindow win : windows.values())
170+
win.alreadyUsed = true;
171+
172+
return pressedKey;
173+
}
174+
175+
public static void destroyWindow(String winname) {
176+
ImageWindow tmpWin = windows.get(winname);
177+
if (tmpWin != null) windows.remove(winname);
178+
}
179+
180+
public static void destroyAllWindows() {
181+
windows.clear();
182+
}
183+
184+
public static void resizeWindow(String winname, int width, int height) {
185+
ImageWindow tmpWin = windows.get(winname);
186+
if (tmpWin != null) tmpWin.setNewDimension(width, height);
187+
}
188+
189+
public static void moveWindow(String winname, int x, int y) {
190+
ImageWindow tmpWin = windows.get(winname);
191+
if (tmpWin != null) tmpWin.setNewPosition(x, y);
192+
}
193+
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package org.opencv.highgui;
2+
3+
import org.opencv.core.Mat;
4+
import org.opencv.core.Size;
5+
import org.opencv.imgproc.Imgproc;
6+
7+
import javax.swing.*;
8+
import java.awt.*;
9+
10+
/**
11+
* This class was designed to create and manipulate
12+
* the Windows to be used by the HighGui class.
13+
*/
14+
public final class ImageWindow {
15+
16+
public final static int WINDOW_NORMAL = 0;
17+
public final static int WINDOW_AUTOSIZE = 1;
18+
19+
public String name;
20+
public Mat img = null;
21+
public Boolean alreadyUsed = false;
22+
public Boolean imgToBeResized = false;
23+
public Boolean windowToBeResized = false;
24+
public Boolean positionToBeChanged = false;
25+
public JFrame frame = null;
26+
public JLabel lbl = null;
27+
public int flag;
28+
public int x = -1;
29+
public int y = -1;
30+
public int width = -1;
31+
public int height = -1;
32+
33+
public ImageWindow(String name, Mat img) {
34+
this.name = name;
35+
this.img = img;
36+
this.flag = WINDOW_NORMAL;
37+
}
38+
39+
public ImageWindow(String name, int flag) {
40+
this.name = name;
41+
this.flag = flag;
42+
}
43+
44+
public static Size keepAspectRatioSize(int original_width, int original_height, int bound_width, int bound_height) {
45+
46+
int new_width = original_width;
47+
int new_height = original_height;
48+
49+
if (original_width > bound_width) {
50+
new_width = bound_width;
51+
new_height = (new_width * original_height) / original_width;
52+
}
53+
54+
if (new_height > bound_height) {
55+
new_height = bound_height;
56+
new_width = (new_height * original_width) / original_height;
57+
}
58+
59+
return new Size(new_width, new_height);
60+
}
61+
62+
public void setMat(Mat img) {
63+
64+
this.img = img;
65+
this.alreadyUsed = false;
66+
67+
if (imgToBeResized) {
68+
resizeImage();
69+
imgToBeResized = false;
70+
}
71+
72+
}
73+
74+
public void setFrameLabelVisible(JFrame frame, JLabel lbl) {
75+
this.frame = frame;
76+
this.lbl = lbl;
77+
78+
if (windowToBeResized) {
79+
lbl.setPreferredSize(new Dimension(width, height));
80+
windowToBeResized = false;
81+
}
82+
83+
if (positionToBeChanged) {
84+
frame.setLocation(x, y);
85+
positionToBeChanged = false;
86+
}
87+
88+
frame.add(lbl);
89+
frame.pack();
90+
frame.setVisible(true);
91+
}
92+
93+
public void setNewDimension(int width, int height) {
94+
95+
if (this.width != width || this.height != height) {
96+
this.width = width;
97+
this.height = height;
98+
99+
if (img != null) {
100+
resizeImage();
101+
} else {
102+
imgToBeResized = true;
103+
}
104+
105+
if (lbl != null) {
106+
lbl.setPreferredSize(new Dimension(width, height));
107+
} else {
108+
windowToBeResized = true;
109+
}
110+
}
111+
}
112+
113+
public void setNewPosition(int x, int y) {
114+
if (this.x != x || this.y != y) {
115+
this.x = x;
116+
this.y = y;
117+
118+
if (frame != null) {
119+
frame.setLocation(x, y);
120+
} else {
121+
positionToBeChanged = true;
122+
}
123+
}
124+
}
125+
126+
private void resizeImage() {
127+
if (flag == WINDOW_NORMAL) {
128+
Size tmpSize = keepAspectRatioSize(img.width(), img.height(), width, height);
129+
Imgproc.resize(img, img, tmpSize);
130+
}
131+
}
132+
}

0 commit comments

Comments
 (0)