Qt+Opencv實(shí)現(xiàn)梯度矯正功能
廢話:
有時(shí)候我們是從物品的斜上方拍攝的圖片,看起來(lái)不直觀,需要把視角拉正,這樣的一個(gè)操作就叫做 梯度矯正,需要用到的技術(shù)是 Opencv 的透視變換。
這個(gè)只是一個(gè)簡(jiǎn)單的演示demo,如果完善一下,比如物品檢測(cè),可以應(yīng)用更多的場(chǎng)景,比如常見(jiàn)的:文件、資料上傳,軟管攝像頭的應(yīng)用等,怎么說(shuō)也是一個(gè)技術(shù)點(diǎn)吧
重要代碼
/** * @brief hDLL_gradientAuto 梯度矯正 * @param src 輸入圖像 * @param dst 輸出圖像 * @param flag 方向,[0(左),1(上),2(右),3(下)] * @param val 矯正度數(shù),像素,[10 ~ 100] * @return 0(成功),-1(失敗) */ int MainWindow::hDLL_gradientAuto(Mat &src, Mat &dst, int flag, int val) { if(flag != 0 && flag != 1 && flag != 2 && flag != 3) return -1; if(val < 10 || val > 100) return -1; int width = src.cols; int height = src.rows; Mat M; // flag 方向,[0(左),1(上),2(右),3(下)] switch (flag) { case 0: { Point2f pts_src[] = { Point(val,val), Point(width, 0), Point(width, height), Point(val, height-val)}; Point2f pts_dst[] = { Point(0, 0), Point(width, 0), Point(width, height) ,Point(0, height) }; M = cv::getPerspectiveTransform(pts_src, pts_dst); }break; case 1: { Point2f pts_src[] = { Point(val,val), Point(width-val, val), Point(width, height), Point(0, height)}; Point2f pts_dst[] = { Point(0, 0), Point(width, 0), Point(width, height) ,Point(0, height) }; M = cv::getPerspectiveTransform(pts_src, pts_dst); }break; case 2: { Point2f pts_src[] = { Point(0,0), Point(width-val, val), Point(width-val, height-val), Point(0, height)}; Point2f pts_dst[] = { Point(0, 0), Point(width, 0), Point(width, height) ,Point(0, height) }; M = cv::getPerspectiveTransform(pts_src, pts_dst); }break; case 3: { Point2f pts_src[] = { Point(0,0), Point(width, 0), Point(width-val, height-val), Point(val, height-val)}; Point2f pts_dst[] = { Point(0, 0), Point(width, 0), Point(width, height) ,Point(0, height) }; M = cv::getPerspectiveTransform(pts_src, pts_dst); }break; } cv::warpPerspective(src, dst, M, dst.size(), cv::INTER_LINEAR , cv::BORDER_REPLICATE); return 0; }
Demo演示
完整代碼
.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QImage> #include <QDebug> #include <QtMath> #include "opencv2/opencv.hpp" using namespace cv; QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); void updateQLabelImage(); Mat QImage2Mat(QImage &img); QImage Mat2QImage(Mat &img); /** * @brief hDLL_gradientAuto 梯度矯正 * @param src 輸入圖像 * @param dst 輸出圖像 * @param flag 方向,[0(左),1(上),2(右),3(下)] * @param val 矯正度數(shù),像素,[10 ~ 100] * @return 0(成功),-1(失敗) */ int hDLL_gradientAuto(Mat &src, Mat &dst, int flag, int val); public slots: void horChange(int index); void verChange(int index); private: Ui::MainWindow *ui; QImage m_img; // 原圖 QImage m_img_dst; // 處理過(guò)的圖像 }; #endif // MAINWINDOW_H
.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); connect(ui->horizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(horChange(int))); connect(ui->verticalSlider, SIGNAL(valueChanged(int)), this, SLOT(verChange(int))); m_img = QImage("F:1.jpg"); m_img_dst = m_img; updateQLabelImage(); } MainWindow::~MainWindow() { delete ui; } // 更新QLabel里面的圖像 void MainWindow::updateQLabelImage() { // m_img = m_img.scaled(ui->label->width(), ui->label->height()); QImage img_show = m_img_dst.scaled(ui->label->width(), ui->label->height()); ui->label->setPixmap(QPixmap::fromImage(img_show)); } Mat MainWindow::QImage2Mat(QImage &img) { cv::Mat mat; switch (img.format()) { case QImage::Format_RGB32: //一般Qt讀入彩色圖后為此格式 mat = cv::Mat(img.height(), img.width(), CV_8UC4, (void*)img.constBits(), img.bytesPerLine()); cv::cvtColor(mat,mat,cv::COLOR_BGRA2BGR); //轉(zhuǎn)3通道 break; case QImage::Format_RGB888: mat = cv::Mat(img.height(), img.width(), CV_8UC3, (void*)img.constBits(), img.bytesPerLine()); cv::cvtColor(mat,mat,cv::COLOR_RGB2BGR); break; case QImage::Format_Indexed8: mat = cv::Mat(img.height(), img.width(), CV_8UC1, (void*)img.constBits(), img.bytesPerLine()); break; } return mat; } QImage MainWindow::Mat2QImage(Mat &img) { if(img.type()==CV_8UC1 || img.type()==CV_8U) { QImage image((const uchar *)img.data, img.cols, img.rows, img.step, QImage::Format_Grayscale8); return image; } else if(img.type()==CV_8UC3) { QImage image((const uchar *)img.data, img.cols, img.rows, img.step, QImage::Format_RGB888); return image.rgbSwapped(); //r與b調(diào)換 } } int MainWindow::hDLL_gradientAuto(Mat &src, Mat &dst, int flag, int val) { if(flag != 0 && flag != 1 && flag != 2 && flag != 3) return -1; if(val < 10 || val > 100) return -1; int width = src.cols; int height = src.rows; Mat M; // flag 方向,[0(左),1(上),2(右),3(下)] switch (flag) { case 0: { Point2f pts_src[] = { Point(val,val), Point(width, 0), Point(width, height), Point(val, height-val)}; Point2f pts_dst[] = { Point(0, 0), Point(width, 0), Point(width, height) ,Point(0, height) }; M = cv::getPerspectiveTransform(pts_src, pts_dst); }break; case 1: { Point2f pts_src[] = { Point(val,val), Point(width-val, val), Point(width, height), Point(0, height)}; Point2f pts_dst[] = { Point(0, 0), Point(width, 0), Point(width, height) ,Point(0, height) }; M = cv::getPerspectiveTransform(pts_src, pts_dst); }break; case 2: { Point2f pts_src[] = { Point(0,0), Point(width-val, val), Point(width-val, height-val), Point(0, height)}; Point2f pts_dst[] = { Point(0, 0), Point(width, 0), Point(width, height) ,Point(0, height) }; M = cv::getPerspectiveTransform(pts_src, pts_dst); }break; case 3: { Point2f pts_src[] = { Point(0,0), Point(width, 0), Point(width-val, height-val), Point(val, height-val)}; Point2f pts_dst[] = { Point(0, 0), Point(width, 0), Point(width, height) ,Point(0, height) }; M = cv::getPerspectiveTransform(pts_src, pts_dst); }break; } cv::warpPerspective(src, dst, M, dst.size(), cv::INTER_LINEAR , cv::BORDER_REPLICATE); return 0; } // 橫向改變 void MainWindow::horChange(int index) { qDebug() << "hor:" << index; if(index == 0) { m_img_dst = m_img; } else if(index < 0) { int val = abs(index) * 10; Mat src = QImage2Mat(m_img); Mat dst; hDLL_gradientAuto(src, dst, 0, val); m_img_dst = Mat2QImage(dst); } else if (index > 0) { int val = abs(index) * 10; Mat src = QImage2Mat(m_img); Mat dst; hDLL_gradientAuto(src, dst, 2, val); m_img_dst = Mat2QImage(dst); } updateQLabelImage(); } // 豎向改變 void MainWindow::verChange(int index) { qDebug() << "ver:" << index; if(index == 0) { m_img_dst = m_img; } else if(index < 0) { int val = abs(index) * 10; Mat src = QImage2Mat(m_img); Mat dst; hDLL_gradientAuto(src, dst, 3, val); m_img_dst = Mat2QImage(dst); } else if (index > 0) { int val = abs(index) * 10; Mat src = QImage2Mat(m_img); Mat dst; hDLL_gradientAuto(src, dst, 1, val); m_img_dst = Mat2QImage(dst); } updateQLabelImage(); }
環(huán)境是:Qt 5.15.2 + Opencv V4.8.0,如果需要下載代碼,自己調(diào)試,自己配置環(huán)境即可
代碼倉(cāng)庫(kù):https://gitee.com/vvvj/qt-test-gradient-auto
以上就是Qt+Opencv實(shí)現(xiàn)梯度矯正功能的詳細(xì)內(nèi)容,更多關(guān)于Qt Opencv梯度矯正的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C++ DLL動(dòng)態(tài)庫(kù)的創(chuàng)建與調(diào)用(類庫(kù),隱式調(diào)用)
本文主要介紹了C++ DLL動(dòng)態(tài)庫(kù)的創(chuàng)建與調(diào)用(類庫(kù),隱式調(diào)用),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05???????C語(yǔ)言實(shí)現(xiàn)單鏈表基本操作方法
這篇文章主要介紹了???????C語(yǔ)言實(shí)現(xiàn)單鏈表基本操作方法,文章圍繞主題展開(kāi)詳細(xì)介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-05-05C++常用的11種設(shè)計(jì)模式解釋及示例代碼詳解
c++常用的設(shè)計(jì)模式包括單例模式、工廠模式、抽象工廠模式、適配器模式、裝飾者模式、代理模式、外觀模式、橋接模式、組合模式、享元模式、觀察者模式和命令模式等,這篇文章主要介紹了C++常用的11種設(shè)計(jì)模式解釋及示例,需要的朋友可以參考下2023-02-02C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易的掃雷小游戲
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易的掃雷小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之迷宮問(wèn)題
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之迷宮問(wèn)題,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-03-03C++詳解哈夫曼樹(shù)的概念與實(shí)現(xiàn)步驟
給定N個(gè)權(quán)值作為N個(gè)葉子結(jié)點(diǎn),構(gòu)造一棵二叉樹(shù),若該樹(shù)的帶權(quán)路徑長(zhǎng)度達(dá)到最小,稱這樣的二叉樹(shù)為最優(yōu)二叉樹(shù),也稱為哈夫曼樹(shù)(Huffman?Tree)。哈夫曼樹(shù)是帶權(quán)路徑長(zhǎng)度最短的樹(shù),權(quán)值較大的結(jié)點(diǎn)離根較近2022-04-04