Necesito obtener todos los datos de píxeles de una imagen en una cadena, con cada píxel tomando 6 caracteres, 2 para cada canal RGB, los estoy almacenando en HEX, por lo que el 0-255 se puede escribir como 00-FF, entonces , por ejemplo, un píxel completamente blanco sería "ffffff" y uno completamente negro "000000".

Este es el código que tengo actualmente, usando OpenCV, toma alrededor de 300ms para una imagen de 288x160:

Mat image = imread("image.jpg");

resize(image, image, Size(288, 160));

Vec3b buf;

stringstream ss;

auto start = high_resolution_clock::now();

for (int i = 0; i < image.rows; i++) {
    for (int j = 0; j < image.cols; j++) {
        buf = image.at<Vec3b>(i, j);
        ss << hex << setfill('0') << setw(2) << (int) buf[0] << setw(2) << (int) buf[1] << setw(2) << (int) buf[2];
    }
}

string output = ss.str();

auto stop = high_resolution_clock::now();

auto duration = duration_cast<milliseconds>(stop - start);

cout << "Execution time: " << duration.count() << " ms" << endl;

¿Existe alguna otra forma mejor / más rápida de hacerlo? Sé que el concepto en sí no es muy eficiente, pero realmente necesito sacarle una cuerda, 300ms no es tan malo tbh, pero cuanto más rápido, mejor

1
Levy Barbosa 7 may. 2021 a las 22:31

1 respuesta

La mejor respuesta

Si la velocidad es un problema, elimine el stringstream por completo y simplemente complete el string manualmente usando algunos cambios de bits para calcular los dígitos hexadecimales, por ejemplo:

Mat image = imread("image.jpg");
resize(image, image, Size(288, 160));

const char *hexDigits = "0123456789abcdef";

auto start = high_resolution_clock::now();

string output((image.rows * image.cols) * 6, '\0');
size_t idx = 0;

for (int i = 0; i < image.rows; ++i) {
    for (int j = 0; j < image.cols; ++j) {
        Vec3b &buf = image.at<Vec3b>(i, j);
        for(int k = 0; k < 3; ++k) {
            uchar ch = buf[k];
            output[idx++] = hexDigits[(ch >> 4) & 0x0F];
            output[idx++] = hexDigits[ch & 0x0F];
        }
    }
}

auto stop = high_resolution_clock::now();

auto duration = duration_cast<milliseconds>(stop - start);

cout << "Execution time: " << duration.count() << " ms" << endl;

Alternativamente, este bucle podría reducir algunos milisegundos adicionales, al no tener que llamar a image.at() para cada píxel individual:

for (int i = 0; i < image.rows; ++i) {
    Vec3b *buf = image.ptr<Vec3b>(i, 0);
    const Vec3b* buf_end = buf + image.cols;
    while (buf != buf_end) {
        for(int k = 0; k < 3; ++k) {
            uchar ch = (*buf)[k];
            output[idx++] = hexDigits[(ch >> 4) & 0x0F];
            output[idx++] = hexDigits[ch & 0x0F];
        }
        ++buf;
    }
}
3
Remy Lebeau 7 may. 2021 a las 20:06