前言

在我的项目中,可能一些输出的图像要求是RGB的图像格式,然而手边只有单通道的黑白相机进行采图,这时就须要将8位的单通道图像转换成24位的三通道图像,个别都是应用3个8位图像叠加成三通道图像。

1、OpenCV实现单通道转三通道

首先创立一个CV_8UC3的三通道图像,图像大小尺寸与单通道图像尺寸统一,而后将3份单通道图像叠加交融填入刚创立的三通道图像。

Mat Widget::convertTo3Channels(const cv::Mat& binImg){    cv::Mat three_channel = cv::Mat::zeros(binImg.rows,binImg.cols,CV_8UC3);    std::vector<cv::Mat> channels;    for (int i=0;i<3;i++)    {        channels.push_back(binImg);    }    cv::merge(channels,three_channel);    return three_channel;}

2、判断图像通道数进行转换

这里先判断图像是否是单通道还是四通道,如果是四通道,将图像间接转换成三通道。如果是单通道应用下面程序转换成三通道

        //判断输出图像的通道数        if(curMatImg.type() == CV_8UC4)        {            cvtColor(curMatImg,curMatImg,COLOR_RGBA2RGB);            qDebug()<<"width"<<curMatImg.cols<<curMatImg.rows;        }        else if(curMatImg.type() == CV_8UC1)        {            curMatImg = convertTo3Channels(curMatImg);        }        else        {            qDebug()<<"Img is 3 Channels";        }

3、程序实现代码

transWidget.h
#ifndef WIDGET_H#define WIDGET_H#include <QWidget>#include <QSettings>#include <QFileInfo>#include <QFileDialog>#include <QDebug>#include <QMessageBox>#include "opencv2/opencv.hpp"namespace Ui {class Widget;}class Widget : public QWidget{    Q_OBJECTpublic:    explicit Widget(QWidget *parent = 0);    ~Widget();private slots:    void on_btn_trans_clicked();    void on_btn_close_clicked();    void on_btn_OpenFile_clicked();    void on_btn_NextPic_clicked();    void on_btn_LoadPic_clicked();    void on_btn_SaveImgPath_clicked();private:    Ui::Widget *ui;    QImage curImg;    //文件夹中图像数量    int PicNum;    //文件夹以后加载图像下标    int CurPicIndex=0;    //批量加载图像文件夹的门路    QString file_path;    //以后图像名称    QString CurfileName;    //图像名称缓存    QMap<int,QString> PicNameInfo;    //保留文件夹文件数量    int saveFile_Num;    //Mat转换QImage    QImage cvMat2QImage(const cv::Mat& mat);    //QImage转换Mat    cv::Mat QImage2Mat(QImage image);    //图像转换到三通道    cv::Mat convertTo3Channels(const cv::Mat& binImg);    void checkCurPicIndex();};#endif // WIDGET_H
transWidget.cpp
#pragma execution_character_set("utf-8")#include "widget.h"#include "ui_widget.h"using namespace cv;Widget::Widget(QWidget *parent) :    QWidget(parent),    ui(new Ui::Widget){    ui->setupUi(this);    ui->btn_NextPic->setEnabled(false);}Widget::~Widget(){    delete ui;}void Widget::on_btn_trans_clicked(){    //保留图像    if(ui->edt_ImgSavePath->text().isEmpty())    {        QMessageBox::critical(NULL, "critical", "未指定保留文件夹,请设置!");        return;    }    else    {        Mat curMatImg = QImage2Mat(curImg);        //判断输出图像是不是8位灰度图像        if(curMatImg.type() == CV_8UC4)        {            cvtColor(curMatImg,curMatImg,COLOR_RGBA2RGB);            qDebug()<<"width"<<curMatImg.cols<<curMatImg.rows;        }        else if(curMatImg.type() == CV_8UC1)        {            curMatImg = convertTo3Channels(curMatImg);        }        else        {            qDebug()<<"Img is 3 Channels";        }        QImage QimgTrans = cvMat2QImage(curMatImg);        QImage ShowTranImg = QimgTrans.scaled(ui->lbl_RGBImg->size(),Qt::KeepAspectRatio);        ui->lbl_RGBImg->setPixmap(QPixmap::fromImage(ShowTranImg));        QString SaveFilePath = ui->edt_ImgSavePath->text() + "/trans_" + QString::number(saveFile_Num) +".bmp";        QimgTrans.save(SaveFilePath);        saveFile_Num++;    }}Mat Widget::QImage2Mat(QImage image){    Mat cvMat;    qDebug()<<image.format();    switch(image.format())    {    case QImage::Format_ARGB32:    case QImage::Format_RGB32:        cvMat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());        cv::cvtColor(cvMat, cvMat, COLOR_BGRA2BGR);        break;    case QImage::Format_ARGB32_Premultiplied:        cvMat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());        break;    case QImage::Format_RGB888:        cvMat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine());        cv::cvtColor(cvMat, cvMat, COLOR_BGR2RGB);        break;    case QImage::Format_Indexed8:        cvMat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());        break;    case QImage::Format_Grayscale8:        cvMat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());        break;    }    return cvMat;}QImage Widget::cvMat2QImage(const cv::Mat &mat){    switch ( mat.type() )    {    // 8-bit  4 channel    case CV_8UC4:    {        QImage image( (const uchar*)mat.data, mat.cols, mat.rows, static_cast<int>(mat.step), QImage::Format_RGB32 );        return image;    }                // 8-bit  3 channel    case CV_8UC3:    {        QImage image( (const uchar*)mat.data, mat.cols, mat.rows, static_cast<int>(mat.step), QImage::Format_RGB888 );        return image.rgbSwapped();    }                // 8-bit  1 channel    case CV_8UC1:    {        static QVector<QRgb> sColorTable;                // only create our color table once                if ( sColorTable.isEmpty() )                    {                        for ( int i = 0; i < 256; ++i )                                sColorTable.push_back( qRgb( i, i, i ) );                    }                QImage image( mat.data, mat.cols, mat.rows, mat.step, QImage::Format_Indexed8 );                image.setColorTable( sColorTable );                return image;    }            default:        qDebug("Image format is not supported: depth=%d and %d channels\n", mat.depth(), mat.channels());        qWarning() << "cvMatToQImage - cv::Mat image type not handled in switch:" << mat.type();        break;    }        return QImage();}Mat Widget::convertTo3Channels(const cv::Mat& binImg){    cv::Mat three_channel = cv::Mat::zeros(binImg.rows,binImg.cols,CV_8UC3);    std::vector<cv::Mat> channels;    for (int i=0;i<3;i++)    {        channels.push_back(binImg);    }    //    cv::merge()    cv::merge(channels,three_channel);    return three_channel;}void Widget::on_btn_close_clicked(){    close();}void Widget::on_btn_OpenFile_clicked(){    QSettings setting("./Setting.ini", QSettings::IniFormat);          //为了能记住上次关上的门路    QString lastPath = setting.value("LastFilePath").toString();        file_path = QFileDialog::getExistingDirectory(this, "请抉择文件夹门路...", lastPath);        if(file_path.isEmpty())    {        QMessageBox::warning(this,"Warning","未抉择文件夹,请从新抉择文件夹!");        return;    }    else    {        PicNameInfo.clear();        CurPicIndex = 0;        QDir dir(file_path);  //改文件夹曾经判断是否存在,保障以后必然存在        QStringList filter;        filter<<"*.bmp"<<"*.jpg"<<"*.png";        QFileInfoList list = dir.entryInfoList(filter, QDir::Files);        //获取文件信息列表        if(!list.isEmpty())        {            //            qDebug() << list.count();//输入图片名            for(int i=0;i<list.count();i++){                QFileInfo fileInfo = list.at(i);                qDebug() << fileInfo.fileName();//输入图片名                PicNameInfo.insert(i,fileInfo.fileName());            }            CurfileName = PicNameInfo.value(0);            QString picPathShow = file_path + "/" + PicNameInfo.value(0);            ui->edt_ImgFolderPath->setText(picPathShow);            curImg.load(picPathShow);            QImage ShowImg = curImg.scaled(ui->lbl_GrayImg->size(),Qt::KeepAspectRatio);            ui->lbl_GrayImg->setPixmap(QPixmap::fromImage(ShowImg));            ui->lbl_RGBImg->clear();            checkCurPicIndex();        }        else        {            QMessageBox::warning(this,"Warning","该文件夹为空,请从新抉择文件夹!");            return;        }    }    }void Widget::on_btn_NextPic_clicked(){    CurPicIndex++;    CurfileName = PicNameInfo.value(CurPicIndex);    QString curPicPath = file_path + "/" + PicNameInfo.value(CurPicIndex);    ui->edt_ImgFolderPath->setText(curPicPath);    curImg.load(curPicPath);    QImage ShowImg = curImg.scaled(ui->lbl_GrayImg->size(),Qt::KeepAspectRatio);    ui->lbl_GrayImg->setPixmap(QPixmap::fromImage(ShowImg));    ui->lbl_RGBImg->clear();    checkCurPicIndex();}void Widget::on_btn_LoadPic_clicked(){    QSettings setting("./Setting.ini", QSettings::IniFormat);          //为了能记住上次关上的门路    QString lastPath = setting.value("LastFilePath").toString();    QFileInfo file;    QString PicPath =QFileDialog::getOpenFileName(this,QString::fromLocal8Bit("抉择图像文件"),lastPath,"图像文件 (*.bmp *.jpg *.png)");        if(PicPath.isEmpty())    {        return;    }    else    {        file = QFileInfo(PicPath);        //            CurfileName = file.fileName();  //获取文件名        //            qDebug() << CurfileName;//输入图片名        qDebug()<<"加载图像胜利";        //        QImage img(PicPath);        curImg.load(PicPath);        QImage ShowImg = curImg.scaled(ui->lbl_GrayImg->size(),Qt::KeepAspectRatio);        ui->lbl_GrayImg->setPixmap(QPixmap::fromImage(ShowImg));        ui->lbl_RGBImg->clear();        //        ui->graphicsView->fitInView(ImageItem);    }}void Widget::checkCurPicIndex(){    if(PicNameInfo.size()>1)    {        if(CurPicIndex == 0)        {            //            ui->btnPreviousPic->setEnabled(false);            ui->btn_NextPic->setEnabled(true);        }        else if(CurPicIndex == PicNameInfo.count()-1)        {            ui->btn_NextPic->setEnabled(false);            //            ui->btnPreviousPic->setEnabled(true);        }        else        {            //            ui->btnPreviousPic->setEnabled(true);            ui->btn_NextPic->setEnabled(true);        }    }    }void Widget::on_btn_SaveImgPath_clicked(){    QSettings setting("./Setting.ini", QSettings::IniFormat);          //为了能记住上次关上的门路    QString lastPath = setting.value("LastFilePath").toString();        QString save_path = QFileDialog::getExistingDirectory(this, "请抉择文件夹门路...", lastPath);    ui->edt_ImgSavePath->setText(save_path);    QDir *dir = new QDir(save_path);    QStringList filter;    QFileInfoList fileInfoList = dir->entryInfoList(filter);    saveFile_Num  = fileInfoList.count()-2;}

4、实现成果

5、源码学习

最初附上源码学习,能够在仓库按需自取,仓库中代码仅供学习应用。
GrayTo3channel