摘要

本篇博文记录一下,用VS+Qt+Halcon实现对图片的读取以及鼠标缩放,移动(鼠标事件调用了halcon自带的算子)的过程。以及遇到的坑.....

先来看一下动态效果图:

主要控件:

  • 添加一个Label控件,对象名设为label,用于显示图片,并将背景设为黑色,设置方法为:选中Label控件,在属性编辑器中找到styleSheet属性,在其后的值中输入background-color:black即可;
  • 添加四个Push Button控件,如上图所示从左至右,对象名依次为:btn_prePic、btn_openPic、btn_nextPic,btn_resetPic,用于打开图片和前后浏览,以及恢复原图;
  • 添加一个Label,对象名设为label_status,用于实时显示坐标和灰度值;
  • 将label_show控件提升为CMyLabel类,用于接收鼠标事件。

代码例程

在Visual Studio中新建一个Qt GUI项目,名称设为BrowsePic,并新建Mylabel类(继承自QLabel)用于label控件的提升。

  • Mylabel.h
#pragma once
#include "qlabel.h"
#include"QWheelEvent"
#include<HalconCpp.h>
using namespace HalconCpp; class Mylabel :
public QLabel
{
Q_OBJECT public:
Mylabel(QWidget* parent = Q_NULLPTR);
~Mylabel();
//设置Halcon图像和Halcon窗口句柄,用户响应鼠标事件后实时更新图像
void setHalconWnd(HObject img, HTuple hHalconID, QLabel* label);
//鼠标滚轮缩放事件
void wheelEvent(QWheelEvent* ev);
//鼠标按下事件
void mousePressEvent(QMouseEvent* ev);
//鼠标释放事件
void mouseReleaseEvent(QMouseEvent* ev);
//鼠标移动事件
void mouseMoveEvent(QMouseEvent* ev);
public:
HTuple m_labelID; //Qt标签句柄
HTuple m_hHalconID; //Halcon窗口句柄
HObject m_currentImg; //当前的图像
//主界面显示坐标的标签
QLabel* m_label;
//鼠标按下的位置
HTuple m_tMouseDownRow;
HTuple m_tMouseDownCol;
bool m_bIsMove; //是否移动图像标识
};
  • Mylabel.cpp
#include "Mylabel.h"
//定义单步放大倍率
#define ZOOMRATIO 2.0 Mylabel::Mylabel(QWidget* parent)
: QLabel(parent)
{
m_bIsMove = false;
this->setMouseTracking(true); }
Mylabel::~Mylabel()
{ } //设置Halcon图像和Halcon窗口句柄,用户响应鼠标事件后实时更新图像
void Mylabel::setHalconWnd(HObject img, HTuple hHalconID, QLabel* label)
{
m_hHalconID = hHalconID;
m_currentImg = img;
m_label = label;
} //鼠标滚轮缩放事件,用于缩放图像
void Mylabel::wheelEvent(QWheelEvent* ev)
{
double Zoom; //放大或缩小倍率
HTuple mouseRow, mouseCol, Button;
HTuple startRowBf, startColBf, endRowBf, endColBf, Ht, Wt, startRowAft, startColAft, endRowAft, endColAft;
//滚轮前滑,放大
if (ev->delta()>0)
{
Zoom = ZOOMRATIO;
}
else//否则缩小
{
Zoom = 1 / ZOOMRATIO;
}
//获取光标在原图上的位置,注意是原图坐标,不是Label下的坐标
HTuple hv_Exception, hv_ErrMsg;
try
{
GetMposition(m_hHalconID, &mouseRow, &mouseCol, &Button); }
catch (HException& HDevExpDefaultException)
{
return;
}
//获取原图显示的部分,注意也是原图坐标
GetPart(m_hHalconID, &startRowBf, &startColBf, &endRowBf, &endColBf);
//缩放前显示的图像宽高
Ht = endRowBf - startRowBf;
Wt = endColBf - startColBf;
//普通版halcon能处理的图像最大尺寸是32K*32K。如果无限缩小原图像,导致显示的图像超出限制,则会造成程序崩溃
if (Ht*Wt<20000*20000||Zoom==ZOOMRATIO)
{
//计算缩放后的图像区域
startRowAft = mouseRow - ((mouseRow - startRowBf) / Zoom);
startColAft = mouseCol - ((mouseCol - startColBf) / Zoom);
endRowAft = startRowAft + (Ht / Zoom);
endColAft = startColAft + (Wt / Zoom);
//如果放大过大,则返回
if (endRowAft - startRowAft < 2)
{
return;
} if (m_hHalconID != NULL)
{
//如果有图像,则先清空图像
DetachBackgroundFromWindow(m_hHalconID);
}
SetPart(m_hHalconID, startRowAft, startColAft, endRowAft, endColAft);
AttachBackgroundToWindow(m_currentImg, m_hHalconID);
}
} void Mylabel::mousePressEvent(QMouseEvent* ev)
{
HTuple mouseRow, mouseCol, Button;
try
{
GetMposition(m_hHalconID, &mouseRow, &mouseCol, &Button); }
catch (HException)
{
return;
}
//鼠标按下时的行列坐标
m_tMouseDownRow = mouseRow;
m_tMouseDownCol = mouseCol;
m_bIsMove = true;
}
//鼠标释放事件
void Mylabel::mouseReleaseEvent(QMouseEvent* ev)
{
m_bIsMove = false;
}
//鼠标移动事件
void Mylabel::mouseMoveEvent(QMouseEvent* ev)
{
HTuple startRowBf, startColBf, endRowBf, endColBf, mouseRow, mouseCol, Button;
try
{
GetMposition(m_hHalconID, &mouseRow, &mouseCol, &Button); }
catch (HException)
{
return;
}
//鼠标按下并移动时,移动图像,否则只显示坐标
if (m_bIsMove)
{
//计算移动值
double RowMove = mouseRow[0].D() - m_tMouseDownRow[0].D();
double ColMove = mouseCol[0].D() - m_tMouseDownCol[0].D();
//得到当前的窗口坐标
GetPart(m_hHalconID, &startRowBf, &startColBf, &endRowBf, &endColBf);
//移动图像
if (m_hHalconID!=NULL)
{
//如果有图像,则先清空图像
DetachBackgroundFromWindow(m_hHalconID);
}
SetPart(m_hHalconID, startRowBf - RowMove, startColBf - ColMove, endRowBf - RowMove, endColBf - ColMove);
AttachBackgroundToWindow(m_currentImg, m_hHalconID);
}
//获取灰度值
HTuple pointGray;
try
{
GetGrayval(m_currentImg, mouseRow, mouseCol, &pointGray);
}
catch (HException)
{
m_label->setText(QString::fromLocal8Bit("X坐标:- Y坐标:- 灰度值:-")); return;
}
//设置坐标
m_label->setText(QString::fromLocal8Bit("X坐标:%1 Y坐标:%2 灰度值:%3").arg(mouseCol[0].D()).arg(mouseRow[0].D()).arg(pointGray[0].D()));
}
  • BrowsePic.h
#pragma once

#include <QtWidgets/QWidget>
#include "ui_BrowsePic.h"
#include<HalconCpp.h>
#include"qtoolbar.h"
using namespace HalconCpp;
#pragma execution_character_set("utf-8"); class BrowsePic : public QWidget
{
Q_OBJECT public:
BrowsePic(QWidget *parent = Q_NULLPTR);
~BrowsePic();
//初始化
void init(); //显示图像
void showImg();
int currentIndex;
//显示图像的控件id
HTuple m_hLabelID; //QLabel控件句柄
HTuple m_hHalconID; //Halcon显示窗口句柄 //原始图像的尺寸
HTuple m_imgWidth, m_imgHeight; //图片路径列表
HTuple m_imgFiles; //当前图像
HObject m_hCurrentImg;
//缩放后的图像
HObject m_hResizedImg;
//缩放系数
HTuple m_hvScaledRate;
//缩放后图像的大小
HTuple m_scaledHeight, m_scaledWidth;
QToolBar* m_toolBar;
public slots: //打开图片
void on_btn_openPic_clicked(); //浏览前一张
void on_btn_prePic_clicked(); //浏览后一张
void on_btn_nextPic_clicked(); //恢复图片
void on_btn_resetPic_clicked();
private:
Ui::BrowsePicClass ui;
};
  • BrowsePic.cpp
#include "browsepic.h"
#include"Mylabel.h"
#include <QFileDialog>
#include <QFileInfo>
BrowsePic::BrowsePic(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this); init(); }
BrowsePic::~BrowsePic()
{ } void BrowsePic::init()
{
//设置halcon的文件路径为utf8,解决中文乱码
SetSystem("filename_encoding", "utf8");
//生成空图像
GenEmptyObj(&m_hCurrentImg);
m_hHalconID = NULL;
m_hLabelID = (Hlong)ui.label->winId();
currentIndex = -1;
}
//显示图像
void BrowsePic::showImg()
{
if (m_hHalconID!=NULL)
{
//如果有图像,则先清空图像
DetachBackgroundFromWindow(m_hHalconID); }
else
{
//打开窗口
OpenWindow(0, 0, ui.label->width(), ui.label->height(), m_hLabelID, "visible", "", &m_hHalconID);
}
ui.label-> setHalconWnd(m_hCurrentImg, m_hHalconID, ui.label_status); //获取图像大小
GetImageSize(m_hCurrentImg, &m_imgWidth, &m_imgHeight);
//获取缩放系数
TupleMin2(1.0 * ui.label->width() / m_imgWidth, 1.0 * ui.label->height() / m_imgHeight, &m_hvScaledRate);
//缩放图像
ZoomImageFactor(m_hCurrentImg, &m_hResizedImg, m_hvScaledRate, m_hvScaledRate, "constant");
//获取缩放后的大小
GetImageSize(m_hResizedImg, &m_scaledWidth, &m_scaledHeight);
//打开窗口
if (1.0 * ui.label->width() / m_imgWidth < 1.0 * ui.label->height() / m_imgHeight)
{
SetWindowExtents(m_hHalconID, ui.label->height() / 2.0 - m_scaledHeight / 2.0, 0, ui.label->width(), m_scaledHeight);
}
else
{
SetWindowExtents(m_hHalconID, 0, ui.label->width() / 2.0 - m_scaledWidth / 2.0, m_scaledWidth, ui.label->height()); }
SetPart(m_hHalconID, 0, 0, m_imgHeight - 1, m_imgWidth - 1);
AttachBackgroundToWindow(m_hCurrentImg, m_hHalconID);
} //打开图片
void BrowsePic::on_btn_openPic_clicked()
{
QString path = QFileDialog::getOpenFileName(this, "加载图像", "./", "图像文件(*.bmp *.png *.jpg)");
QFileInfo fileInfo(path);
QString dir = fileInfo.path(); if (!path.isEmpty())
{
ListFiles(dir.toStdString().c_str(), "files", &m_imgFiles); TupleRegexpSelect(m_imgFiles, HTuple("\\.bmp|png|jpg").Append("ignore_case"), &m_imgFiles); for (int i = 0; i < m_imgFiles.Length(); i++)
{ QString currentPath = m_imgFiles[i];
currentPath.replace("\\", "/"); if (currentPath == path)
{
currentIndex = i;
ReadImage(&m_hCurrentImg, m_imgFiles[i]);
showImg();
} }
} } //浏览前一张
void BrowsePic::on_btn_prePic_clicked()
{
if (currentIndex > 0)
{
currentIndex--;
ReadImage(&m_hCurrentImg, m_imgFiles[currentIndex]);
showImg(); }
}
//浏览后一张
void BrowsePic::on_btn_nextPic_clicked()
{
if (currentIndex >= 0 && currentIndex < m_imgFiles.Length() - 1)
{
currentIndex++;
ReadImage(&m_hCurrentImg, m_imgFiles[currentIndex]);
showImg();
}
}
//恢复图片
void BrowsePic::on_btn_resetPic_clicked()
{
showImg();
}

关键代码解释

1️⃣Qt函数与Halcon算子获取的文件路径字符串的区别

  • Halcon算子获取的文件路径格式

list_files()的原型如下:

第一个参数为路径,提取的文件路径格式与参数Directory的形式有关,在HDevelop中测试:

– Directory以"\\"分隔时,即list_files ('E:\\TEST', 'files', Files)

– Directory以“/”分隔时,即list_files ('E:/TEST', 'files', Files)

可以发现两种方式提取的文件路径字符串的区别。

  • Qt函数获取的文件路径格式

getOpenFileName()获得的路径:

如何将二者路径保持一致?

先读取halcon算子获取的路径:

            QString currentPath = m_imgFiles[i];

然后将" \ "全部换成" /":

            currentPath.replace("\\", "/");

2️⃣在VS中使用Halcon时的编码及中文乱码问题

默认条件下,可使用以下C++语句获取Halcon的文件名编码:

HTuple codeType;
get_system("filename_encoding", &codeType);
QString strCodeType = codeType[0].S();

可以发现默认的编码是locale,此时用Halcon算子list_files获取的文件路径中如果包含中文,则会出现乱码

解决方法:将Halcon的文件名编码格式设置为utf8,代码如下:

set_system("filename_encoding", "utf8");

参考链接:(4条消息) VS+Qt应用开发-使用Halcon算子实现从文件夹打开图片、前后浏览、缩放居中显示_羽士的博客-CSDN博客

VS+Qt+Halcon——显示图片,实现鼠标缩放、移动图片的更多相关文章

  1. arcgis 加载png图片实现图片跟随地图缩放 和图片的动态播放

    效果图: 主要原理: png加载到地图上是不可能的, 图像本身是没有地理信息的. 这里采用一种办法, 在地图上创建一个图形图层, 图形图层放一个矩形,给这个矩形用一个图片填充符号填充. 关键技术点: ...

  2. 20.QT-Qpixmap实现图片鼠标缩放,鼠标拖动示例(详解)

    通过 QPainter 绘画实现,以本地图片985*740为例 如下图所示: 效果如下所示: 实现原理 主要通过以下函数实现: , ); //平铺显示pixmap //x y w h :表示绘画区域 ...

  3. Magnifier.js - 支持鼠标滚轮缩放的图片放大镜效果

    Magnifier.js 是一个 JavaScript 库,能够帮助你在图像上实现放大镜效果,支持使用鼠标滚轮放大/缩小功能.放大的图像可以显示在镜头本身或它的外部容器中.Magnifier.js 使 ...

  4. QT中给各控件增加背景图片(可缩放可旋转)的几种方法

    http://blog.csdn.net/liukang325/article/details/44832397 1. 给QPushButton 增加背景图片:背景图片可根据Button大小自由缩放. ...

  5. Discuz!图片查看插件(支持鼠标缩放、实际大小、旋转、下载)

    Discuz!图片查看插件(支持鼠标缩放.实际大小.旋转.下载) 图片查看是网站中的常用功能,用于展示详细的图片.在discuz图片插件的基础上进行了改造,因此这篇文章主要从以下几个方面来讨论图片查看 ...

  6. jQuery hover事件鼠标滑过图片半透明标题文字滑动显示隐藏

    1.效果及功能说明 hover事件制作产品图片鼠标滑过图片半透明,标题文字从左到右滑动动画移动显示隐藏 2.实现原理 首先把效果都隐藏,然后定义一个伪类来触发所有的效果,接下来当触发伪类后会有一个遍历 ...

  7. 一天JavaScript示例-点击图片显示大图片添加鼠标

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  8. C#,一种简单的方式实现滚动鼠标缩放图片,平移

    1.缩放 private void ImageShow_Load(object sender, EventArgs e) { pictureBox1.Load(@"E:\SQ1.jpg&qu ...

  9. 在WPF里面实现以鼠标位置为中心缩放移动图片

    原文:在WPF里面实现以鼠标位置为中心缩放移动图片 在以前的文章使用WPF Resource以及Transform等技术实现鼠标控制图片缩放和移动的效果里面,介绍了如何在WPF里面移动和放大缩小图片, ...

随机推荐

  1. HGAME_easyVM

    64位的exe,拖入ida64静态分析一波. 一.先是一大堆的赋值语句,有点懵,后面在分析handler的时候,也直接导致了我卡壳,这里还是得注意一下这些局部变量都是临近的,所以可以直接看成一个连续数 ...

  2. C# 8.0和.NET Core 3.0高级编程 分享笔记三:控制流程和转换类型

    控制流程和转换类型 本章的内容主要包括编写代码.对变量执行简单的操作.做出决策.重复执行语句块.将变量或表达式值从一种类型转换为另一种类型.处理异常以及在数值变量中检查溢出. 本章涵盖以下主题: 操作 ...

  3. 重置networker8.0密码

    一.重置Networker 8.0密码 1.设置环境变量 新建一个"系统环境变量"名字为"GST_RESET_PW",值为1 2.重启EMC GST Servi ...

  4. Nginx PHP测试装

    Nginx yum -y install gcc gcc-c++ make automake autoconf pcre pcre-devel zlib zlib-devel openssl open ...

  5. 「CF576D」 Flights for Regular Customers

    「CF576D」 Flights for Regular Customers 对不起我又想网络流去了 你看这长得多像啊,走过至少多少条边就是流量下界,然后没上界 但是这个题求的最少走多少条边啊...完 ...

  6. 必须要了解的Linux基本操作

    Linux常用的基础操作             1.命令行提示字符             2.切换用户             3.查看当前主机的完整名称             4.临时设置主机 ...

  7. ICMP、ARP协议介绍和ping命令

    交换机工作原理和常用的简单命令    一.ICMP协议      1)ICMP协议的封装    二.ARP协议      1)什么是ARP协议      2)ARP相关命令    三.Ping命令的使 ...

  8. C语言:3个数排序

    #include <stdio.h> int main() { int a,b,c,t; /*定义4个基本整型变量a.b.c.t*/ printf("Please input a ...

  9. Pytest单元测试框架之FixTure内置临时文件tmpdir操作

    1.前言:某些接口需要引用上个接口返回的值,作为下个接口的入参,但笔者又不想在本地维护及创建此文件,此时引出fixture内置函数中的临时文件存储tmpdir 2.首先下面的源码是使用flask框架写 ...

  10. 简单快速安装Apache+PHP+MySql服务环境(三)—— 下载安装phpmyadmin

    为了方便在Linux上操作mysql数据库,打算安装一个phpmyadmin,不过在下载安装的过程中出现了一些坑,特此记录. 1. 在官网上下载phpmyadmin https://files.php ...