图片格式的快速转换: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图片,就可以看到保存的灰度图了。
本文结束。