yuv_viewer_gui.cpp

00001
00002 /***************************************************************************
00003  *  yuv_viewer.cpp - YUV viewer gui
00004  *
00005  *  Created:  Sat Mar 22 16:34:02 2009
00006  *  Copyright 2009 Christof Rath <c.rath@student.tugraz.at>
00007  *
00008  ****************************************************************************/
00009
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU Library General Public License for more details.
00019  *
00020  *  Read the full text in the LICENSE.GPL file in the doc directory.
00021  */
00022
00023 #include "yuv_viewer_gui.h"
00024
00025 #include <fvutils/color/colorspaces.h>
00026 #include <fvutils/draw/drawer.h>
00027
00028 #include <cmath>
00029 #include <cstring>
00030 #include <iomanip>
00031 #include <sstream>
00032
00033 #define M_2xPI (2*M_PI)
00034 using namespace fawkes;
00035 
00036 /** @class YuvViewerGtkWindow "yuv_viewer_gui.h"
00037  * Tool to show the YUV color space
00038  *
00039  * @author Christof Rath
00040  */
00041 
00042 /** Constructor.
00043  * @param cobject C base object
00044  * @param ref_xml Glade XML
00045  */
00046 YuvViewerGtkWindow::YuvViewerGtkWindow(BaseObjectType* cobject,
00047                                        const Glib::RefPtr<Gnome::Glade::Xml> ref_xml)
00048   : Gtk::Window(cobject)
00049 {
00050   ref_xml->get_widget("yuv_vp",  __yuv_vp);
00051   ref_xml->get_widget("cur_vp",  __cur_vp);
00052   ref_xml->get_widget("seg_vp",  __seg_vp);
00053   ref_xml->get_widget("y_scale", __y_scale);
00054   ref_xml->get_widget("u_value", __u_value);
00055   ref_xml->get_widget("v_value", __v_value);
00056   ref_xml->get_widget("y_res",   __y_res);
00057   ref_xml->get_widget("u_res",   __u_res);
00058   ref_xml->get_widget("v_res",   __v_res);
00059
00060   __yuv_widget = Gtk::manage(new ImageWidget(256, 256));
00061   __cur_widget = Gtk::manage(new ImageWidget( 60, 40));
00062   __seg_widget = Gtk::manage(new ImageWidget(256, 256));
00063
00064   __y_scale->signal_value_changed().connect(sigc::mem_fun(*this, &YuvViewerGtkWindow::on_y_value_changed));
00065   __y_res->signal_value_changed().connect(sigc::mem_fun(*this, &YuvViewerGtkWindow::on_y_res_changed));
00066   __u_res->signal_value_changed().connect(sigc::mem_fun(*this, &YuvViewerGtkWindow::on_uv_res_changed));
00067   __v_res->signal_value_changed().connect(sigc::mem_fun(*this, &YuvViewerGtkWindow::on_uv_res_changed));
00068
00069   __yuv_vp->signal_button_press_event().connect(sigc::mem_fun(*this, &YuvViewerGtkWindow::on_click_on_yuv));
00070   __yuv_vp->signal_motion_notify_event().connect(sigc::mem_fun(*this, &YuvViewerGtkWindow::on_mouse_over_yuv));
00071   __yuv_vp->add(*__yuv_widget);
00072   __cur_vp->add(*__cur_widget);
00073   __seg_vp->add(*__seg_widget);
00074
00075
00076   memset(__cur_buffer + 60 * 40, 128,  60 * 40);
00077   memset(__seg_buffer, 128, 256 * 256);
00078   on_y_value_changed();
00079   on_uv_res_changed();
00080   calc_seg();
00081   show_all_children();
00082 }
00083 
00084 /** Destructor. */
00085 YuvViewerGtkWindow::~YuvViewerGtkWindow()
00086 {
00087 }
00088 
00089 /** Signal hander that gets called after a click on the YUV pane
00090  * @param event provides the x/y-coordinate
00091  * @return true
00092  */
00093 bool
00094 YuvViewerGtkWindow::on_click_on_yuv(GdkEventButton *event)
00095 {
00096   GdkEventMotion mot;
00097   mot.x = event->x;
00098   mot.y = event->y;
00099   return on_mouse_over_yuv(&mot);
00100 }
00101 
00102 /** Signal hander that gets called during a movement on the YUV pane (if the left button is pressed)
00103  * @param event provides the x/y-coordinate
00104  * @return true
00105  */
00106 bool
00107 YuvViewerGtkWindow::on_mouse_over_yuv(GdkEventMotion *event)
00108 {
00109   unsigned int u = std::max(0, std::min(255, (int)event->x));
00110   unsigned int v = 255 - std::max(0, std::min(255, (int)event->y));
00111
00112   __u_value->set_text(convert_float2str(u, 0));
00113   __v_value->set_text(convert_float2str(v, 0));
00114   memset(__cur_buffer + 60 * 40, u,  60 * 20);
00115   memset(__cur_buffer + 60 * 60, v,  60 * 20);
00116   __cur_widget->show(YUV422_PLANAR, __cur_buffer);
00117
00118   return true;
00119 }
00120 
00121 /** Signal handler called when the Y value changes (HSlider) */
00122 void
00123 YuvViewerGtkWindow::on_y_value_changed()
00124 {
00125   unsigned int y = round(__y_scale->get_value());
00126   memset(__yuv_buffer, y, 256 * 256);
00127   memset(__cur_buffer, y, 60 * 40);
00128
00129   Drawer d;
00130   d.set_buffer(__yuv_buffer, 256, 256);
00131   d.set_color(YUV_t::black());
00132   d.draw_line(127, 127, 0, 64);
00133   d.draw_line(127, 127, 64, 0);
00134
00135   d.draw_line(128, 127, 192, 0);
00136   d.draw_line(128, 127, 255, 64);
00137
00138   d.draw_line(128, 128, 192, 255);
00139   d.draw_line(128, 128, 255, 192);
00140
00141   d.draw_line(127, 128, 0, 192);
00142   d.draw_line(127, 128, 64, 255);
00143
00144   __yuv_widget->show(YUV422_PLANAR, __yuv_buffer);
00145   __cur_widget->show(YUV422_PLANAR, __cur_buffer);
00146 }
00147
00148
00149 void
00150 YuvViewerGtkWindow::on_y_res_changed()
00151 {
00152   unsigned int r = round(__y_res->get_value());
00153
00154   if (r == 0) {
00155     __y_scale->set_value(127);
00156     __y_scale->set_range(127, 128);
00157   }
00158   else {
00159     __y_scale->set_range(0, 255);
00160     __y_scale->set_increments(255.f / (pow(2, r) - 1), 0);
00161   }
00162 }
00163
00164 void
00165 YuvViewerGtkWindow::on_uv_res_changed()
00166 {
00167   unsigned char *yuv_u = __yuv_buffer + 256 * 256;
00168   unsigned char *yuv_v = yuv_u + 256 * 256 / 2;
00169   unsigned int u_div = 256 / (int)pow(2, __u_res->get_value());
00170   unsigned int v_div = 256 / (int)pow(2, __v_res->get_value());
00171
00172   for (unsigned int v = 0; v < 256; ++v) {
00173     memset((yuv_v + v * 128), ((255 - v) / v_div) * v_div, 128);
00174
00175     for (unsigned int u = 0; u < 128; ++u) {
00176       yuv_u[v * 128 + u] = (u * 2 / u_div) * u_div;
00177     }
00178   }
00179
00180   on_y_value_changed();
00181 }
00182 
00183 /**
00184  * Converts a float value to a Glib::ustring (locale dependent)
00185  * @param f The float value
00186  * @param width The precision width
00187  * @return the formatted string
00188  */
00189 Glib::ustring
00190 YuvViewerGtkWindow::convert_float2str(float f, unsigned int width)
00191 {
00192 #if GLIBMM_MAJOR_VERSION > 2 || ( GLIBMM_MAJOR_VERSION == 2 && GLIBMM_MINOR_VERSION >= 16 )
00193   return Glib::ustring::format(std::fixed, std::setprecision(width), f);
00194 #else
00195   std::ostringstream ss;
00196   ss << std::fixed << std::setprecision(width);
00197   ss << f;
00198
00199   return Glib::locale_to_utf8(ss.str());
00200 #endif
00201 }
00202 
00203 /** Calculates the segmented window */
00204 void
00205 YuvViewerGtkWindow::calc_seg()
00206 {
00207   YUV_t c;
00208   unsigned char *seg_u = __seg_buffer + 256 * 256;
00209   unsigned char *seg_v = seg_u + 256 * 256 / 2;
00210
00211   float a1 = atan2f(64, 128);
00212   float a2 = atan2f(128, 64);
00213   float a3 = atan2f(128, -64);
00214   float a4 = atan2f(64, -128);
00215   float a5 = atan2f(-64, -128) + M_2xPI;
00216   float a6 = atan2f(-128, -64) + M_2xPI;
00217   float a7 = atan2f(-128, 64) + M_2xPI;
00218   float a8 = atan2f(-64, 128) + M_2xPI;
00219
00220   for (int u = 0; u < 256; ++u) {
00221     float du = u - 128;
00222
00223     for (int v = 255; v >= 0; --v) {
00224       float dv = v - 128;
00225
00226       if (!du) {
00227         if (dv > 0) YUV_t::red();
00228         else c = YUV_t::gray();
00229       }
00230       else {
00231         float a = atan2f(dv, du);
00232         if (a < 0) a += M_2xPI;
00233
00234         if (a >= a1 && a < a2) c = YUV_t::magenta();
00235         else if (a >= a2 && a < a3) c = YUV_t::red();
00236         else if (a >= a3 && a < a4) c = YUV_t::orange();
00237         else if (a >= a4 && a < a5) c = YUV_t::yellow();
00238         else if (a >= a5 && a < a6) c = YUV_t::green();
00239         else if (a >= a6 && a < a7) c = YUV_t::gray();
00240         else if (a >= a7 && a < a8) c = YUV_t::cyan();
00241         else c = YUV_t::blue();
00242       }
00243
00244       unsigned int addr = ((255 - v) * 256 + u) / 2;
00245       seg_u[addr] = c.U;
00246       seg_v[addr] = c.V;
00247     }
00248   }
00249
00250   __seg_widget->show(YUV422_PLANAR, __seg_buffer);
00251 }