Fawkes API Fawkes Development Version
yuv_viewer_gui.cpp
1
2/***************************************************************************
3 * yuv_viewer.cpp - YUV viewer gui
4 *
5 * Created: Sat Mar 22 16:34:02 2009
6 * Copyright 2009 Christof Rath <c.rath@student.tugraz.at>
7 *
8 ****************************************************************************/
9
10/* This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * Read the full text in the LICENSE.GPL file in the doc directory.
21 */
22
23#include "yuv_viewer_gui.h"
24
25#include <fvutils/color/colorspaces.h>
26#include <fvutils/draw/drawer.h>
27
28#include <cmath>
29#include <cstring>
30#include <iomanip>
31#include <sstream>
32
33#define M_2xPI (2 * M_PI)
34using namespace fawkes;
35using namespace firevision;
36
37/** @class YuvViewerGtkWindow "yuv_viewer_gui.h"
38 * Tool to show the YUV color space
39 *
40 * @author Christof Rath
41 */
42
43/** Constructor.
44 * @param cobject C base object
45 * @param builder Gtk builder
46 */
48 const Glib::RefPtr<Gtk::Builder> builder)
49: Gtk::Window(cobject)
50{
51 builder->get_widget("yuv_vp", yuv_vp_);
52 builder->get_widget("cur_vp", cur_vp_);
53 builder->get_widget("seg_vp", seg_vp_);
54 builder->get_widget("y_scale", y_scale_);
55 builder->get_widget("u_value", u_value_);
56 builder->get_widget("v_value", v_value_);
57 builder->get_widget("y_res", y_res_);
58 builder->get_widget("u_res", u_res_);
59 builder->get_widget("v_res", v_res_);
60
61 yuv_widget_ = Gtk::manage(new ImageWidget(256, 256));
62 cur_widget_ = Gtk::manage(new ImageWidget(60, 40));
63 seg_widget_ = Gtk::manage(new ImageWidget(256, 256));
64
65 y_scale_->signal_value_changed().connect(
66 sigc::mem_fun(*this, &YuvViewerGtkWindow::on_y_value_changed));
67 y_res_->signal_value_changed().connect(
68 sigc::mem_fun(*this, &YuvViewerGtkWindow::on_y_res_changed));
69 u_res_->signal_value_changed().connect(
70 sigc::mem_fun(*this, &YuvViewerGtkWindow::on_uv_res_changed));
71 v_res_->signal_value_changed().connect(
72 sigc::mem_fun(*this, &YuvViewerGtkWindow::on_uv_res_changed));
73
74 yuv_vp_->signal_button_press_event().connect(
75 sigc::mem_fun(*this, &YuvViewerGtkWindow::on_click_on_yuv));
76 yuv_vp_->signal_motion_notify_event().connect(
77 sigc::mem_fun(*this, &YuvViewerGtkWindow::on_mouse_over_yuv));
78 yuv_vp_->add(*yuv_widget_);
79 cur_vp_->add(*cur_widget_);
80 seg_vp_->add(*seg_widget_);
81
82 memset(cur_buffer_ + 60 * 40, 128, 60 * 40);
83 memset(seg_buffer_, 128, 256 * 256);
84 on_y_value_changed();
85 on_uv_res_changed();
86 calc_seg();
87 show_all_children();
88}
89
90/** Destructor. */
92{
93}
94
95/** Signal hander that gets called after a click on the YUV pane
96 * @param event provides the x/y-coordinate
97 * @return true
98 */
99bool
100YuvViewerGtkWindow::on_click_on_yuv(GdkEventButton *event)
101{
102 GdkEventMotion mot;
103 mot.x = event->x;
104 mot.y = event->y;
105 return on_mouse_over_yuv(&mot);
106}
107
108/** Signal hander that gets called during a movement on the YUV pane (if the left button is pressed)
109 * @param event provides the x/y-coordinate
110 * @return true
111 */
112bool
113YuvViewerGtkWindow::on_mouse_over_yuv(GdkEventMotion *event)
114{
115 unsigned int u = std::max(0, std::min(255, (int)event->x));
116 unsigned int v = 255 - std::max(0, std::min(255, (int)event->y));
117
118 u_value_->set_text(convert_float2str(u, 0));
119 v_value_->set_text(convert_float2str(v, 0));
120 memset(cur_buffer_ + 60 * 40, u, 60 * 20);
121 memset(cur_buffer_ + 60 * 60, v, 60 * 20);
122 cur_widget_->show(YUV422_PLANAR, cur_buffer_);
123
124 return true;
125}
126
127/** Signal handler called when the Y value changes (HSlider) */
128void
129YuvViewerGtkWindow::on_y_value_changed()
130{
131 unsigned int y = round(y_scale_->get_value());
132 memset(yuv_buffer_, y, 256 * 256);
133 memset(cur_buffer_, y, 60 * 40);
134
135 Drawer d;
136 d.set_buffer(yuv_buffer_, 256, 256);
137 d.set_color(YUV_t::black());
138 d.draw_line(127, 127, 0, 64);
139 d.draw_line(127, 127, 64, 0);
140
141 d.draw_line(128, 127, 192, 0);
142 d.draw_line(128, 127, 255, 64);
143
144 d.draw_line(128, 128, 192, 255);
145 d.draw_line(128, 128, 255, 192);
146
147 d.draw_line(127, 128, 0, 192);
148 d.draw_line(127, 128, 64, 255);
149
150 yuv_widget_->show(YUV422_PLANAR, yuv_buffer_);
151 cur_widget_->show(YUV422_PLANAR, cur_buffer_);
152}
153
154void
155YuvViewerGtkWindow::on_y_res_changed()
156{
157 unsigned int r = round(y_res_->get_value());
158
159 if (r == 0) {
160 y_scale_->set_value(127);
161 y_scale_->set_range(127, 128);
162 } else {
163 y_scale_->set_range(0, 255);
164 y_scale_->set_increments(255.f / (pow(2, r) - 1), 0);
165 }
166}
167
168void
169YuvViewerGtkWindow::on_uv_res_changed()
170{
171 unsigned char *yuv_u = yuv_buffer_ + 256 * 256;
172 unsigned char *yuv_v = yuv_u + 256 * 256 / 2;
173 unsigned int u_div = 256 / (int)pow(2, u_res_->get_value());
174 unsigned int v_div = 256 / (int)pow(2, v_res_->get_value());
175
176 for (unsigned int v = 0; v < 256; ++v) {
177 memset((yuv_v + v * 128), ((255 - v) / v_div) * v_div, 128);
178
179 for (unsigned int u = 0; u < 128; ++u) {
180 yuv_u[v * 128 + u] = (u * 2 / u_div) * u_div;
181 }
182 }
183
184 on_y_value_changed();
185}
186
187/**
188 * Converts a float value to a Glib::ustring (locale dependent)
189 * @param f The float value
190 * @param width The precision width
191 * @return the formatted string
192 */
193Glib::ustring
194YuvViewerGtkWindow::convert_float2str(float f, unsigned int width)
195{
196#if GLIBMM_MAJOR_VERSION > 2 || (GLIBMM_MAJOR_VERSION == 2 && GLIBMM_MINOR_VERSION >= 16)
197 return Glib::ustring::format(std::fixed, std::setprecision(width), f);
198#else
199 std::ostringstream ss;
200 ss << std::fixed << std::setprecision(width);
201 ss << f;
202
203 return Glib::locale_to_utf8(ss.str());
204#endif
205}
206
207/** Calculates the segmented window */
208void
209YuvViewerGtkWindow::calc_seg()
210{
211 YUV_t c;
212 unsigned char *seg_u = seg_buffer_ + 256 * 256;
213 unsigned char *seg_v = seg_u + 256 * 256 / 2;
214
215 float a1 = atan2f(64, 128);
216 float a2 = atan2f(128, 64);
217 float a3 = atan2f(128, -64);
218 float a4 = atan2f(64, -128);
219 float a5 = atan2f(-64, -128) + M_2xPI;
220 float a6 = atan2f(-128, -64) + M_2xPI;
221 float a7 = atan2f(-128, 64) + M_2xPI;
222 float a8 = atan2f(-64, 128) + M_2xPI;
223
224 for (int u = 0; u < 256; ++u) {
225 float du = u - 128;
226
227 for (int v = 255; v >= 0; --v) {
228 float dv = v - 128;
229
230 if (!du) {
231 if (dv > 0)
232 YUV_t::red();
233 else
234 c = YUV_t::gray();
235 } else {
236 float a = atan2f(dv, du);
237 if (a < 0)
238 a += M_2xPI;
239
240 if (a >= a1 && a < a2)
241 c = YUV_t::magenta();
242 else if (a >= a2 && a < a3)
243 c = YUV_t::red();
244 else if (a >= a3 && a < a4)
245 c = YUV_t::orange();
246 else if (a >= a4 && a < a5)
247 c = YUV_t::yellow();
248 else if (a >= a5 && a < a6)
249 c = YUV_t::green();
250 else if (a >= a6 && a < a7)
251 c = YUV_t::gray();
252 else if (a >= a7 && a < a8)
253 c = YUV_t::cyan();
254 else
255 c = YUV_t::blue();
256 }
257
258 unsigned int addr = ((255 - v) * 256 + u) / 2;
259 seg_u[addr] = c.U;
260 seg_v[addr] = c.V;
261 }
262 }
263
264 seg_widget_->show(YUV422_PLANAR, seg_buffer_);
265}
YuvViewerGtkWindow(BaseObjectType *cobject, const Glib::RefPtr< Gtk::Builder > builder)
Constructor.
virtual ~YuvViewerGtkWindow()
Destructor.
Draw to an image.
Definition: drawer.h:32
void set_color(unsigned char y, unsigned char u, unsigned char v)
Set drawing color.
Definition: drawer.cpp:71
void draw_line(unsigned int x_start, unsigned int y_start, unsigned int x_end, unsigned int y_end)
Draw line.
Definition: drawer.cpp:363
void set_buffer(unsigned char *buffer, unsigned int width, unsigned int height)
Set the buffer to draw to.
Definition: drawer.cpp:58
This class is an image container to display fawkes cameras (or image buffers) inside a Gtk::Container...
Definition: image_widget.h:43
virtual bool show(colorspace_t colorspace, unsigned char *buffer, unsigned int width=0, unsigned int height=0)
Show image from given colorspace.
Fawkes library namespace.
YUV pixel.
Definition: yuv.h:58
unsigned char V
V component.
Definition: yuv.h:61
unsigned char U
U component.
Definition: yuv.h:60