图片格式的快速转换:Opencv的Mat格式转换为leptonica的PIX格式

写这篇博客的原因是,原来网上能找到的Opencv::Mat转leptonica_pix格式效率实在太低了,例如,很多人采用了下面的办法来进行转换

https://stackoverflow.com/questions/39293922/convert-between-opencv-mat-and-leptonica-pix

Pix *mat8ToPix(cv::Mat *mat8)
{
    Pix *pixd = pixCreate(mat8->size().width, mat8->size().height, 8);
    for(int y=0; y<mat8->rows; y++) {
        for(int x=0; x<mat8->cols; x++) {
            pixSetPixel(pixd, x, y, (l_uint32) mat8->at<uchar>(y,x));
        }
    }
    return pixd;
}

cv::Mat pix8ToMat(Pix *pix8)
{
    cv::Mat mat(cv::Size(pix8->w, pix8->h), CV_8UC1);
    uint32_t *line = pix8->data;
    for (uint32_t y = 0; y < pix8->h; ++y) {
        for (uint32_t x = 0; x < pix8->w; ++x) {
            mat.at<uchar>(y, x) = GET_DATA_BYTE(line, x);
        }
        line += pix8->wpl;
    }
    return mat;
}
这也就意味着,每个像素都必须进行一次函数级的栈操作,同时还要进行row*width的乘法操作,大部分时间都在算地址,所以我参考了leptonica的源码,作了下面的修改,
Pix* mat8ToPix(unsigned char* pdata, int width, int height, int channels = 1)
{
    assert(1 == channels); // this function is specifically for grayscale images 
    int depth = 8 * channels;
    int stride = width * channels;
    unsigned char* p_var = pdata;
    Pix* pixd = pixCreate(width, height, depth);
    l_int32    w, h, d, wpl;
    pixGetDimensions(pixd, &w, &h, &d);
    wpl = pixd->wpl;
    int wpl_t = stride / 4;
    wpl_t += ((width - wpl_t*4 > 0) ? 1 : 0);
    assert(wpl == wpl_t);
    l_uint32* pline = pixd->data;
    for (int y = 0; y < height; y++) {
        p_var = pdata + y * width;
        pline =  pixd->data + y * wpl;
        for (int x = 0; x < width; x++) {
            //ref. pixSetPixel(pixd, x, y, (l_uint32)p_var[x]); // little-endian to big-endian        
            l_uint32 val = (l_uint32)p_var[x];    
            switch (d)
            {
            case 1:
                if (val)
                    SET_DATA_BIT(pline, x);
                else
                    CLEAR_DATA_BIT(pline, x);
                break;
            case 2:
                SET_DATA_DIBIT(pline, x, val);
                break;
            case 4:
                SET_DATA_QBIT(pline, x, val);
                break;
            case 8:
                SET_DATA_BYTE(pline, x, val);
                break;
            case 16:
                SET_DATA_TWO_BYTES(pline, x, val);
                break;
            case 32:
                pline[x] = val;
                break;
            default:
                return NULL;
            }
        }
    }
    return pixd;
}

这里,输入的pdata必须是grayscale的,下面是测试代码,

const char* img_name = "test4r.png";

cv::Mat img = cv::imread(img_name, cv::IMREAD_GRAYSCALE);


if (img.empty()) {
    std::cout << "Read image failed" << std::endl;
}

PIX* pix = mat8ToPix(img.data, img.cols, img.rows, img.channels());

//pixWritePng("my_test_pix.png", pix, 1);

pixWrite("my_test_pix.png", pix, 1);

然后,打开my_test_pix.png图片,就可以看到保存的灰度图了。

本文结束。

posted @ 2022-07-23 15:00  SpaceVision  阅读(386)  评论(0编辑  收藏  举报