Qt加Opencv实现 梯度矫正 功能
废话:
有时候我们是从物品的斜上方拍摄的图片,看起来不直观,需要把视角拉正,这样的一个操作就叫做 梯度矫正,需要用到的技术是 Opencv 的 透视变换。
这个只是一个简单的演示demo,如果完善一下,比如物品检测,可以应用更多的场景,比如常见的:文件、资料上传,软管摄像头的应用等,怎么说也是一个技术点吧
重要代码:
/**
* @brief hDLL_gradientAuto 梯度矫正
* @param src 输入图像
* @param dst 输出图像
* @param flag 方向,[0(左),1(上),2(右),3(下)]
* @param val 矫正度数,像素,[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 矫正度数,像素,[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; // 处理过的图像
};
#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); //转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调换
}
} 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();
}
代码下载:
我的环境是:Qt 5.15.2 + Opencv V4.8.0,如果需要下载代码,自己调试,自己配置环境即可
代码仓库:https://gitee.com/vvvj/qt-test-gradient-auto
Qt加Opencv实现 梯度矫正 功能的更多相关文章
- windows平台下基于QT和OpenCV搭建图像处理平台
在之前的博客中,已经分别比较详细地阐述了"windows平台下基于VS和OpenCV"以及"Linux平台下基于QT和OpenCV"搭建图像处理框架,并 ...
- Qt:&OpenCV—Q图像处理基本操作(Code)
原文链接:http://www.cnblogs.com/emouse/archive/2013/03/31/2991333.html 作者写作一系列:http://www.cnblogs.com/em ...
- QT与openCV,与PCL结合!
(1):详解QT多媒体框架:给予视频播放器 原文链接:http://mobile.51cto.com/symbian-271123.htm 对于使用主框架的QT程序,实现Qimage的转换可借鉴下面程 ...
- CUDA加opencv复现导向滤波算法
CUDA是GPU通用计算的一种,其中现在大热的深度学习底层GPU计算差不多都选择的CUDA,在这我们先简单了解下其中的一些概念,为了好理解,我们先用DX11里的Compute shader来和CUDA ...
- QT+OPENCV实现录屏功能
本文使用QT+opencv来实现对指定窗体画面录制,并保存为avi文件. (1)获取窗体界面 QScreen类有一个grabWindow函数,可以用来获取窗体的画面,这个函数使用很简单,就是传入窗体句 ...
- 使用QT显示OpenCV读取的图片
目录 1. 概述 2. 实现 2.1. 代码 2.2. 解析 3. 结果 1. 概述 OpenCV自带了一部分常用的GUI功能,但是更多的图像处理功能需要其他GUI框架来辅助实现,这里通过QT来显示O ...
- 基于PI+QT实现OpenCV图像处理操作(基本环境搭建)
这篇博客就是在PI上直接写出来的!cheers!! PI3的性能已经非常强劲,而作为一个能够独立运行的运算单元,使用它来做图像处理,将是非常适合的.为了挖掘机器的最大潜能,我没有采用比较常见的pyth ...
- 基于QT和OpenCV的人脸检測识别系统(2)
紧接着上一篇博客的讲 第二步是识别部分 人脸识别 把上一阶段检測处理得到的人脸图像与数据库中的已知 人脸进行比对,判定人脸相应的人是谁(此处以白色文本显示). 人脸预处理 如今你已经得到一张人脸,你能 ...
- 【OpenCV】透视变换矫正
演示结果参考: 功能实现:运行程序,会显示图片的尺寸,按回车键后,依次点击需矫正的图片的左上.右上.左下.右下角,并能显示其坐标,结果弹出矫正后的图片,如图上的PIC2对话框.可以继续选择图片四个点进 ...
- 项目实战:Qt+Ffmpeg+OpenCV相机程序(打开摄像头、支持多种摄像头、分辨率调整、翻转、旋转、亮度调整、拍照、录像、回放图片、回放录像)
若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...
随机推荐
- JS中Date和时间戳转换
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="C ...
- 【Azure 应用服务】记一次Azure Spring Cloud 的部署错误 (az spring-cloud app deploy -g dev -s testdemo -n demo -p ./hellospring-0.0.1-SNAPSHOT.jar --->>> Failed to wait for deployment instances to be ready)
问题描述 使用Azure Spring Cloud服务,在部署时候失败,收到错误消息为: c:\project\hellospring>az spring-cloud app deploy -g ...
- 智联招聘基于 Nebula Graph 的推荐实践分享
本文首发于 Nebula Graph Community 公众号 本文整理自智联招聘资深工程师李世明在「智联招聘推荐场景应用」的实践分享 搜索推荐架构 在讲具体的应用场景之前,我们先看下智联招聘搜索和 ...
- BeanShell Sample 如何使用?
一 引入: eanShell Sample主要用于生成一些逻辑复杂的数据,例如用于加解密数据: **每次调用前重置bsh.Interpreter:每个BeanShell副本都有自己的解释器副本(每个线 ...
- C++ //set/multiset 容器 //set不可以插入重复的数字 multiset可以插入重复的数字 //ste容器构造和赋值 //set大小和交换 //set 插入和删除 //set查找和统计 //set 和 multiset 区别 //pair 对组创建 //set存放自定义数据类型 //set内置数据 进行排序
1 //set/multiset 容器 //set不可以插入重复的数字 multiset可以插入重复的数字 2 //ste容器构造和赋值 //set大小和交换 //set 插入和删除 3 //set查 ...
- XWAF安装遇到的坑
存在的问题:需要的编译环境没有安装配置好的话出现下面的问题: 1.error: Microsoft Visual C++ 14.0 or greater is required. Get it wit ...
- Git 如何删除本地分支和远程分支
查看已有的本地及远程分支:git branch -a 删除远程分支(当前删除的是origin/dev分支):git push origin --delete dev 删除后,再次查看分支情况: ...
- JAVA 多线程---面经
线程与进程 提到进程那就要说程序,程序有指令和数据,程序从磁盘加载到内存,cpu获得指令进行执行,其中还会用到各种资源如网络资源,磁盘等.一个程序从磁盘进入内存,就是进程实例的创建. 一个程序可以有多 ...
- Centos安装常见软件
一.vscode sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc sudo sh -c 'echo -e &qu ...
- Kotlin学习快速入门(12)—— 位运算符
由于不懂pythod,最近拜托朋友研究下解密live2d模型的解密算法,朋友写出了Java的代码 之后我进行改版,在转为kotlin的时候,发现kotlin自动转换有些坑,以及kotlin中的位运算符 ...