¿Hay alguna manera de codificar JPEG a una tasa de bits específica?¿Cómo especificar la tasa de bits para la compresión JPEG?
Actualmente, estoy usando ImageMagick de convert
:
convert Lenna-gray-100.jpeg -quality 1.1111 test.jpeg
aumenta la velocidad de bits con calidad, pero es no lineal. Quiero controlar la velocidad de bits de forma explícita. No tiene que ser exacto, pero lo quiero razonablemente cerca (dentro de, por ejemplo, 0.1 bpp de la configuración especificada).
¿Hay algún codificador allí que permita codificar las imágenes a una velocidad de bits determinada? No tiene que ser imagemagick, tomaré lo que funcione (preferiblemente en Linux).
Una forma estúpida de hacer esto sería jugar con los valores fraccionarios del parámetro -quality
hasta que salga algo cercano a la tasa de bits objetivo, pero estoy esperando una solución más elegante.
EDIT:
Así que me aburría y decidió hacer las cosas de manera rápida (pero estúpida).
En primer lugar, aquí hay un gráfico de la -quality
ImageMagick vs tasa de bits:
Por cierto, aquí está la imagen que utilicé:
lo tanto, el cambio en la tasa de bits es bastante bien para valores de calidad más bajos, pero se vuelve grueso después de aproximadamente 80.
Aquí hay un código de muestra para codificar una imagen a una tasa de bits objetivo. Utilicé OpenCV porque permite la codificación JPEG en la memoria (no es necesaria la E/S). Aunque originalmente iba a simular esto con Python, desafortunadamente los envoltorios Python OpenCV no exponen la funcionalidad de codificación en memoria. Así que lo escribí en C++.
Por último, estaba pensando en utilizar la interpolación lineal en la calidad para acercarme a la tasa de bits objetivo, pero como cv::imencode
solo acepta parámetros enteros, no es posible establecer una calidad JPEG no entera. La escala de calidad entre OpenCV y imagemagick también parece diferir, así que tomar el parámetro de calidad interpolado de OpenCV y usar en imagemagick's convert
no funcionó bien.
Esto significa que la tasa de bits de salida no es igual a la tasa de bits objetivo, especialmente a tasas de bits más altas (> 1). Pero está cerca.
¿Alguien puede sugerir algo mejor?
Código:
#include <stdio.h>
#include <cv.h>
#include <highgui.h>
#include <assert.h>
#include <vector>
using cv::Mat;
using std::vector;
#define IMENCODE_FMT ".jpeg"
#define QUALITY_UBOUND 101
#define BITS_PER_BYTE 8
int
main(int argc, char **argv)
{
if (argc != 4)
{
fprintf(stderr, "usage: %s in.png out.jpeg bpp\n", argv[0]);
return 1;
}
char *fname_in = argv[1];
char *fname_out = argv[2];
float target;
sscanf(argv[3], "%f", &target);
Mat orig = cv::imread(fname_in);
int pixels = orig.size().width * orig.size().height * orig.channels();
vector<unsigned char> buf;
vector<int> params = vector<int>(2);
params[0] = CV_IMWRITE_JPEG_QUALITY;
int q;
double bpp = 0.0;
for (q = 1; q < QUALITY_UBOUND; ++q)
{
params[1] = q;
cv::imencode(IMENCODE_FMT, orig, buf, params);
bpp = (double)buf.size() * BITS_PER_BYTE/pixels;
if (bpp > target)
break;
}
cv::imwrite(fname_out, orig, params);
printf("wrote %s at %d%% quality, %.2fbpp\n", fname_out, q, bpp);
return 0;
}
compilar y ejecutar usando:
g++ -c -Wall -ggdb -I../c -I../blur `pkg-config --cflags opencv` -Wno-write-strings jpeg-bitrate.cpp -o jpeg-bitrate.o
g++ -I../c `pkg-config --cflags opencv` `pkg-config --libs opencv` -lboost_filesystem jpeg-bitrate.o -o jpeg-bitrate.out
rm jpeg-bitrate.o
[email protected]:~/co/cpp$ ./jpeg-bitrate.out Lenna-gray.png test.jpeg 0.53
wrote test.jpeg at 88% quality, 0.55bpp
Sugerencia: elimine el bucle for, reemplace con la búsqueda. No puedo creer que alguien quiera un JPEG codificado con factores de calidad en los rangos de 1-> ~ 30 o ~ 99-> 100. También puede crear su gráfico para una variedad de tipos de imágenes diferentes y encontrar un mejor punto de inicio inicial para la búsqueda. Todo esto es muy ingenuo porque ni siquiera considera la calidad (por ejemplo, PSNR); elegir una tabla de cuantificación diferente puede obtener la tasa de bits que desea pero una calidad mucho más alta. – koan
Gracias por la sugerencia. La búsqueda mejorará la eficiencia del código, pero en este momento no es realmente una preocupación porque es lo suficientemente rápido como es. Tiene razón sobre la calidad: la mayoría de las personas normales no necesitan archivos JPEG de esa baja calidad porque parecen basura. Sin embargo, yo mismo * estoy * interesado en tales imágenes, ya que estoy estudiando las degradaciones de la imagen. El punto sobre las tablas de cuantificación es interesante, creo que lo investigaré. Probablemente requerirá alejarse de OpenCV y usar algo como ijg, porque OpenCV no parece exponer las tablas de cuantificación. – misha