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 ...
随机推荐
- 【Azure 环境】ARM部署模板大于4MB的解决方案及Linked Template遇见存储账号防火墙无法访问
问题一:在ADF Pipeline部署ARM Template报错"Deployment failed -- the request content size exceeds the max ...
- Nebula Graph 源码解读系列 | Vol.02 详解 Validator
整体架构 Nebula Graph Query Engine 主要分为四个模块,分别是 Parser.Validator.Optimizer 和 Executor. Parser 完成对语句的词法语法 ...
- RocketMQ(1) 基础介绍和单机-集群安装
1. MQ简单介绍 1.1 应用场景 应用解耦 系统的耦合性越高,容错性就越低.以电商应用为例,用户创建订单后,如果耦合调用库存系统.物流系统.支付系统,任何一个子系统出了故障或者因为升级等原因暂时不 ...
- Codeforces Round 922 (Div. 2)(A~D)补题
A题考虑贪心,要使使用的砖头越多,每块转的k应尽可能小,最小取2,最后可能多出来,多出来的就是最后一块k=3,我们一行内用到的砖头就是\(\frac{m}{2}\)下取整,然后乘以行数就是答案. #i ...
- Delete `␍`
新电脑遇到的问题 Delete `␍`eslint(prettier/prettier) 网上一搜,一堆解决办法,没有一个说到点子上,都是表面上如何避免,如何设置VSCODE... 都知道是换行符的问 ...
- Python面向对象之面向对象编程
[一]什么是面向过程 [1]面向过程介绍 面向过程,核心在于 "过程" 二字 过程的终极奥义就是将程序 "流程化" 过程是 "流水线" ,用 ...
- 春风吹又生的开源项目「GitHub 热点速览」
随着上周知名 Switch 开源模拟器 Yuzu(柚子)被任天堂起诉,该项目作者就删库了,但还是要赔偿任天堂数百万美元.此事还在 GitHub 上掀起了一波 Yuzu fork 项目的小浪潮,正所谓野 ...
- SoftCnKiller 更新程序 bat 调用vbs 更新,下载gitee文件 更新自身数据
bat @echo off title 更新流氓软件黑名单 cd /d "%~dp0" echo 请选择更新源,默认使用1.GitCode更新. echo.&choice ...
- ElasticSearch 准实时原理
Elasticsearch 是一个基于 Lucene 库的搜索引擎.它提供了一个准实时的.分布式.支持多租户的全文搜索引擎. ----维基百科 那么问题来了,为啥 Elasticsearch 不是实时 ...
- Spring Boot学习日记
学习了springboot 的优点 为所有Spring开发者更快的入门 开箱即用,提供各种默认配置来简化项目配置 内嵌式容器简化Web项目 没有冗余代码生成和XML配置的要求 Spring开发-Hel ...