## OpenCV 學習 (Split 和 Merge)
我們在圖像處理時,經常要單獨對某一個顏色通道進行處理。這時可以利用 Opencv 提供的 split 和 merge 函數。
### split 函數
用于將一幅多通道的圖像的各個通道分離。
這個函數的原型如下:
~~~
void split(const Mat& src, vector<Mat_<_Tp> >& mv)
~~~
用法很簡單,src 是一幅多通道的圖像。
mv 保存各個通道,每個通道存放到一個 mat 中。
### merge 函數
merge 與split 函數相反。可以將多個單通道圖像合成一幅多通道圖像。
函數原型如下:
~~~
void merge(const Mat* mv, size_t count, OutputArray dst);
void merge(const vector<Mat>& mv, OutputArray dst );
~~~
這兩個函數非常簡單,所以就不舉例子了。
有時,我用Qt寫的小程序中也需要這個功能,又不想為了這么點小功能就使用 opencv。所以就自己山寨了兩個函數。(其實是這篇博客實在是太短了,要找些內容來湊數)
兩個函數的函數聲明如下:
~~~
QList<QImage> split(const QImage &image);
QImage merge(const QImage &channel_R, const QImage &channel_G, const QImage &channel_B);
~~~
這里 merge 函數只能合并 3 個顏色通道。如果需要 alpha 通道,可以在這個代碼基礎上修改。
下面是代碼,不多解釋。希望對大家有用。
~~~
#include <QImage>
#include <QVector>
inline static bool isContinuous(const QImage &image)
{
bool ret = false;
switch(image.format())
{
case QImage::Format_Indexed8:
ret = image.bytesPerLine() == image.width();
break;
case QImage::Format_ARGB32:
case QImage::Format_RGB32:
case QImage::Format_ARGB32_Premultiplied:
case QImage::Format_RGBX8888:
case QImage::Format_RGBA8888:
case QImage::Format_RGBA8888_Premultiplied:
case QImage::Format_BGR30:
case QImage::Format_A2BGR30_Premultiplied:
case QImage::Format_RGB30:
case QImage::Format_A2RGB30_Premultiplied:
ret = image.bytesPerLine() == 4 * image.width();
break;
case QImage::Format_RGB16:
case QImage::Format_RGB555:
case QImage::Format_RGB444:
case QImage::Format_ARGB4444_Premultiplied:
ret = image.bytesPerLine() == 2 * image.width();
break;
case QImage::Format_ARGB6666_Premultiplied:
case QImage::Format_ARGB8565_Premultiplied:
case QImage::Format_RGB666:
case QImage::Format_ARGB8555_Premultiplied:
case QImage::Format_RGB888:
ret = image.bytesPerLine() == 3 * image.width();
case QImage::Format_Mono:
case QImage::Format_MonoLSB:
ret = image.byteCount()* 8 == image.width() * image.height();
default:
ret = false;
break;
}
return ret;
}
QImage merge(const QImage &channel_R, const QImage &channel_G, const QImage &channel_B)
{
if(channel_R.size() != channel_G.size() || channel_R.size() != channel_B.size())
{
return QImage();
}
if(channel_R.format() != QImage::Format_Indexed8 ||
channel_G.format() != QImage::Format_Indexed8 ||
channel_B.format() != QImage::Format_Indexed8)
{
return QImage();
}
QImage image(channel_R.size(), QImage::Format_RGB32);
int width = image.width();
int height = image.height();
if(isContinuous(image) && isContinuous(channel_B) && isContinuous(channel_G) && isContinuous(channel_R))
{
// 如果圖像占用的內存是連續的,則可以只用一個循環來處理
width = width * height;
height = 1;
}
for(int j = 0; j < height; j++)
{
QRgb* line = (QRgb*) image.scanLine(j);
const uchar * r = channel_R.constScanLine(j);
const uchar * g = channel_G.constScanLine(j);
const uchar * b = channel_B.constScanLine(j);
for(int i = 0; i < width; i++)
{
line[i] = qRgb(r[i], g[i], b[i]);
}
}
return image;
}
QList<QImage> split(const QImage &image)
{
QList<QImage> rgb;
if(image.isNull())
{
return rgb;
}
QImage::Format f = image.format();
if(f == QImage::Format_RGB32 || f == QImage::Format_ARGB32 || f == QImage::Format_ARGB32_Premultiplied)
{
rgb.append(QImage());
rgb.append(QImage());
rgb.append(QImage());
rgb[0] = QImage(image.size(), QImage::Format_Indexed8);
rgb[1] = QImage(image.size(), QImage::Format_Indexed8);
rgb[2] = QImage(image.size(), QImage::Format_Indexed8);
for(int i = 0; i < 256; i++)
{
rgb[0].setColor(i, qRgb(i, 0, 0));
rgb[1].setColor(i, qRgb(0, i, 0));
rgb[2].setColor(i, qRgb(0, 0, i));
}
int width = image.width();
int height = image.height();
for(int j = 0; j < height; j++)
{
const QRgb* line = (QRgb*) image.constScanLine(j);
uchar * line_r = rgb[0].scanLine(j);
uchar * line_g = rgb[1].scanLine(j);
uchar * line_b = rgb[2].scanLine(j);
for(int i = 0; i < width; i++)
{
line_r[i] = qRed(line[i]);
line_g[i] = qGreen(line[i]);
line_b[i] = qBlue(line[i]);
}
}
}
return rgb;
}
~~~