Anec-notas (III)

Las vacaciones no siempre son vacaciones al 100%, cuando se trabaja en el mundo informático lo normal es pasear por todo el país con el portátil a cuestas y tener que realizar cambios sobre la marcha o pequeños ajustes a algún proyecto. Y dado que ya estaba en ésas he acá la tercera entrega de anéc-notas.

QImage

Entre los ajustes que he tenido que hacer hay uno que se refiere a la adquisición de imágenes a 60fps desde diferentes modelos de sensores. El flujo de datos involucra la visualización de dichos fotogramas en una interfaz programada en Qt. Sin entrar en más detalles, la imagen la adquiría en un QImage para su representación. Luego, con el fin de procesarla con otros algoritmos intermedios, obtenía el puntero al bloque de datos mediante un QImage::bits(). De ahí surgen los dos comentarios de esta sección.

El primero es que dicho arreglo de bytes puede contener un padding final, por lo que los píxeles de una fila no están a continuación de la anterior, sino después de un pequeño espacio. Esto no ocurre si la imagen ha sido creada desde un puntero (lo cual evita hacer una copia del bloque de memoria), pero si la imagen se manipula o se crea de otra forma hay que tener en cuenta este espacio.

El otro detalle me pareció muy curioso. Este método tiene dos variantes, una “const” y otra “no-const”. La diferencia principal es que la variante “no-const” crea una copia antes de devolver el puntero, por lo que cualquier optimización que uno crea que está haciendo al acceder directamente al bloque de memoria puede irse al pozo si no tenemos cuidado, por ejemplo, si hacemos algo como:

swap_rgb_to_gbr(img.bits());

Y la función es algo de este estilo:

void swap_rgb_to_gbr(unsigned char *pixels);

La mejor solución que he podido encontrar implica forzar un casting:

const unsigned char *buffer = img.bits();
swap_rgb_to_gbr(const_cast< unsigned char* >(buffer));

Ahora bien, cuando se trata de cambiar el tamaño de una imagen, QImage es poco más que un niño de 2 años con unos lápices de colores en la mano. Lo mejor es utilizar opciones más potentes, como por ejemplo OpenCV (asumiremos que src es ya una imagen de OpenCV válida):

cv::Mat dst;
cv::resize(src, dst, cv::Size(nuevo_ancho, nuevo_alto), 0.0, 0.0, cv::INTER_LANCZOS4);

QImage resizedimg(nuevo_ancho, nuevo_alto, QImage::Format_RGB888); // 24bits por píxel

const unsigned char *dstdata = dst.data;
const int rowsize = nuevo_ancho * 3; // RGB
for (int ii = 0; ii < nuevo_anchoe; ++ii, dstdata += rowsize)
 memcpy(resizedimg.scanLine(ii), dstdata, rowsize);

QMenu

En lo particular me gusta tener un menú “Debug” en el cual puedo incorporar funcionalidades de depuración o que sólo deban estar presente durante el desarrollo, tales como recargar el fichero de estilos, por ejemplo. A fin de simplificar el desarrollo, este menú está siempre presente, y si la aplicación no está siendo compilada en modo depuración se quita.

Hago mención de dicho proceso acá porque no me fue evidente encontrar el cómo se hacía, así que lo dejo por escrito.

ui.menubar->removeAction(ui.menuDebug->menuAction());

Otro detalle sobre los menús es cómo establecer su color de fondo y de texto. Acá dejo un stylesheet de ejemplo.

/* Barra de menu */
QMenuBar
{
 background-image: url(:/someimage.jpeg);
}

/* Elementos de la barra de menú: título de cada menú */
QMenuBar::item
{
 background-color: transparent;
 color: #999999;
}
QMenuBar::item:selected
{
 background-color: transparent;
 color: #ffffff;
}

/* Cada menú */
QMenu
{
 background-color: #444444;
 color: #999999;
}

/* Cada acción del menú */
QMenu::item
{
 background-color: #444444;
}
QMenu::item:selected
{
 color: #ffffff;
}

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.