8 Stimmen

Wie wird die Bitrate für die JPEG-Komprimierung festgelegt?

Gibt es eine Möglichkeit, JPEG mit einer bestimmten Bitrate zu kodieren?

Zurzeit verwende ich imagemagicks convert :

convert Lenna-gray-100.jpeg -quality 1.1111 test.jpeg

Die Bitrate steigt mit der Qualität, aber sie ist nicht linear. Ich möchte die Bitrate explizit steuern. Sie muss nicht exakt sein, aber ich möchte, dass sie einigermaßen genau ist (innerhalb von, sagen wir, 0,1 bpp der angegebenen Einstellung).

Gibt es einen Encoder, mit dem Bilder mit einer bestimmten Bitrate kodiert werden können? Es muss nicht imagemagick sein, ich nehme alles, was funktioniert (vorzugsweise unter Linux).

Ein dummer Weg, dies zu tun, wäre das Herumspielen mit Bruchwerten in der -quality Parameter, bis etwas in der Nähe der Zielbitrate herauskommt, aber ich hoffe auf eine elegantere Lösung.

EDIT :

Also habe ich mich gelangweilt und beschlossen, die Dinge auf die schnelle (aber dumme) Art zu erledigen.

Zunächst ein Diagramm von imagemagick's -quality gegenüber der Bitrate:

alt text

Übrigens, hier ist das Bild, das ich verwendet habe:

alt text

Die Änderung der Bitrate ist also bei niedrigeren Qualitätswerten recht gut, wird aber ab etwa 80 grob.

Hier ist ein Beispielcode zur Kodierung eines Bildes mit einer bestimmten Zielbitrate. Ich habe OpenCV verwendet, weil es eine speicherinterne JPEG-Kodierung ermöglicht (kein I/O notwendig). Ursprünglich wollte ich das mit Python nachbauen, aber leider stellen die Python OpenCV Wrapper die In-Memory Kodierungsfunktionalität nicht zur Verfügung. Also habe ich es in C++ geschrieben.

Schließlich dachte ich an eine lineare Interpolation der Qualität, um näher an die Zielbitrate heranzukommen, aber da cv::imencode nur ganzzahlige Parameter akzeptiert, ist es nicht möglich, eine nicht-ganzzahlige JPEG-Qualität einzustellen. Die Qualitätsskala zwischen OpenCV und imagemagick scheint auch etwas unterschiedlich zu sein, so dass der interpolierte Qualitätsparameter von OpenCV und die Verwendung in imagemagick's convert hat nicht gut funktioniert.

Dies bedeutet, dass die Ausgangsbitrate nicht mit der Zielbitrate übereinstimmt, insbesondere bei höheren Bitraten ( > 1). Aber sie ist nahe dran.

Kann jemand etwas Besseres vorschlagen?

Code:

#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;
}

Kompilieren und ausführen mit:

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
misha@misha-desktop:~/co/cpp$ ./jpeg-bitrate.out Lenna-gray.png test.jpeg 0.53
wrote test.jpeg at 88% quality, 0.55bpp

4voto

BlueCookie Punkte 576

Ich weiß, dass es viele Arbeiten zur Kontrolle der Ausgabe-Bitrate eines JPEG-Encoders gibt (z. B. 1. Papier ; 2. Papier ), und dass solche Kontrollen in JPEG2000 vorhanden sind. Leider bin ich mir nicht sicher, ob irgendeine Art von Bitratenkontrolle für JPEG standardisiert oder in gängigen Bibliotheken implementiert ist. Möglicherweise müssen Sie Ihre eigene Methode zu codieren, mit einer Art von binären Suche zum Beispiel ...

Aber auch hier kann ich mich irren - und wenn dem so ist, würde ich gerne etwas über eine solche Bibliothek erfahren.

Nur aus Neugierde: Welche Sprache verwenden Sie?

2voto

zulu lala Punkte 21

Das Verhältnis zwischen Bitrate und Qualität bei JPG hängt stark vom Inhalt ab. Wenn Sie mit einer bestimmten Bitrate kodieren wollen, empfehle ich Ihnen zwei Durchgänge: 1. Enkodierung mit einem festen Qualitätsfaktor (näher an der Zielbitrate ist besser, könnte auf Ihrer Grafik basieren) 2. Kodieren Sie das Original je nach Größe mit einer höheren oder niedrigeren Qualität neu. Auch dies kann auf der Grundlage Ihres Diagramms oder etwas Ähnlichem erfolgen.

Sie können den letzten Schritt auch beliebig oft wiederholen, um die EXAKTE Bitrate zu erhalten, die Sie benötigen.

Ich würde dies mit verschiedenen Extremfällen testen, z. B. einem sehr verrauschten/verschmutzten Bild, einem schwarzen Rechteck oder einem glatten Farbverlauf.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X