VS+Qt+Halcon 顯示圖片,實現(xiàn)鼠標(biāo)縮放、移動圖片
摘要
本篇博文記錄一下,用VS+Qt+Halcon實現(xiàn)對圖片的讀取以及鼠標(biāo)縮放,移動(鼠標(biāo)事件調(diào)用了halcon自帶的算子)的過程。以及遇到的坑.....😑😑
先來看一下動態(tài)效果圖:

主要控件:
- 添加一個Label控件,對象名設(shè)為label,用于顯示圖片,并將背景設(shè)為黑色,設(shè)置方法為:選中Label控件,在屬性編輯器中找到styleSheet屬性,在其后的值中輸入background-color:black即可;
- 添加四個Push Button控件,如上圖所示從左至右,對象名依次為:btn_prePic、btn_openPic、btn_nextPic,btn_resetPic,用于打開圖片和前后瀏覽,以及恢復(fù)原圖;
- 添加一個Label,對象名設(shè)為label_status,用于實時顯示坐標(biāo)和灰度值;
- 將label_show控件提升為CMyLabel類,用于接收鼠標(biāo)事件。
代碼例程
在Visual Studio中新建一個Qt GUI項目,名稱設(shè)為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();
//設(shè)置Halcon圖像和Halcon窗口句柄,用戶響應(yīng)鼠標(biāo)事件后實時更新圖像
void setHalconWnd(HObject img, HTuple hHalconID, QLabel* label);
//鼠標(biāo)滾輪縮放事件
void wheelEvent(QWheelEvent* ev);
//鼠標(biāo)按下事件
void mousePressEvent(QMouseEvent* ev);
//鼠標(biāo)釋放事件
void mouseReleaseEvent(QMouseEvent* ev);
//鼠標(biāo)移動事件
void mouseMoveEvent(QMouseEvent* ev);
public:
HTuple m_labelID; //Qt標(biāo)簽句柄
HTuple m_hHalconID; //Halcon窗口句柄
HObject m_currentImg; //當(dāng)前的圖像
//主界面顯示坐標(biāo)的標(biāo)簽
QLabel* m_label;
//鼠標(biāo)按下的位置
HTuple m_tMouseDownRow;
HTuple m_tMouseDownCol;
bool m_bIsMove; //是否移動圖像標(biāo)識
};
Mylabel.cpp
#include "Mylabel.h"
//定義單步放大倍率
#define ZOOMRATIO 2.0
Mylabel::Mylabel(QWidget* parent)
: QLabel(parent)
{
m_bIsMove = false;
this->setMouseTracking(true);
}
Mylabel::~Mylabel()
{
}
//設(shè)置Halcon圖像和Halcon窗口句柄,用戶響應(yīng)鼠標(biāo)事件后實時更新圖像
void Mylabel::setHalconWnd(HObject img, HTuple hHalconID, QLabel* label)
{
m_hHalconID = hHalconID;
m_currentImg = img;
m_label = label;
}
//鼠標(biāo)滾輪縮放事件,用于縮放圖像
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;
}
//獲取光標(biāo)在原圖上的位置,注意是原圖坐標(biāo),不是Label下的坐標(biāo)
HTuple hv_Exception, hv_ErrMsg;
try
{
GetMposition(m_hHalconID, &mouseRow, &mouseCol, &Button);
}
catch (HException& HDevExpDefaultException)
{
return;
}
//獲取原圖顯示的部分,注意也是原圖坐標(biāo)
GetPart(m_hHalconID, &startRowBf, &startColBf, &endRowBf, &endColBf);
//縮放前顯示的圖像寬高
Ht = endRowBf - startRowBf;
Wt = endColBf - startColBf;
//普通版halcon能處理的圖像最大尺寸是32K*32K。如果無限縮小原圖像,導(dǎo)致顯示的圖像超出限制,則會造成程序崩潰
if (Ht*Wt<20000*20000||Zoom==ZOOMRATIO)
{
//計算縮放后的圖像區(qū)域
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;
}
//鼠標(biāo)按下時的行列坐標(biāo)
m_tMouseDownRow = mouseRow;
m_tMouseDownCol = mouseCol;
m_bIsMove = true;
}
//鼠標(biāo)釋放事件
void Mylabel::mouseReleaseEvent(QMouseEvent* ev)
{
m_bIsMove = false;
}
//鼠標(biāo)移動事件
void Mylabel::mouseMoveEvent(QMouseEvent* ev)
{
HTuple startRowBf, startColBf, endRowBf, endColBf, mouseRow, mouseCol, Button;
try
{
GetMposition(m_hHalconID, &mouseRow, &mouseCol, &Button);
}
catch (HException)
{
return;
}
//鼠標(biāo)按下并移動時,移動圖像,否則只顯示坐標(biāo)
if (m_bIsMove)
{
//計算移動值
double RowMove = mouseRow[0].D() - m_tMouseDownRow[0].D();
double ColMove = mouseCol[0].D() - m_tMouseDownCol[0].D();
//得到當(dāng)前的窗口坐標(biāo)
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坐標(biāo):- Y坐標(biāo):- 灰度值:-"));
return;
}
//設(shè)置坐標(biāo)
m_label->setText(QString::fromLocal8Bit("X坐標(biāo):%1 Y坐標(biāo):%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;
//當(dāng)前圖像
HObject m_hCurrentImg;
//縮放后的圖像
HObject m_hResizedImg;
//縮放系數(shù)
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();
//恢復(fù)圖片
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()
{
//設(shè)置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);
//獲取縮放系數(shù)
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();
}
}
//恢復(fù)圖片
void BrowsePic::on_btn_resetPic_clicked()
{
showImg();
}
關(guān)鍵代碼解釋
Qt函數(shù)與Halcon算子獲取的文件路徑字符串的區(qū)別
Halcon算子獲取的文件路徑格式
list_files()的原型如下:

第一個參數(shù)為路徑,提取的文件路徑格式與參數(shù)Directory的形式有關(guān),在HDevelop中測試:
–Directory以"\\"分隔時,即list_files ('E:\\TEST', 'files', Files)

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

可以發(fā)現(xiàn)兩種方式提取的文件路徑字符串的區(qū)別。
Qt函數(shù)獲取的文件路徑格式
getOpenFileName()獲得的路徑:

如何將二者路徑保持一致?
先讀取halcon算子獲取的路徑:
QString currentPath = m_imgFiles[i];

然后將" \ "全部換成" /":
currentPath.replace("\\", "/");

2️⃣在VS中使用Halcon時的編碼及中文亂碼問題
默認(rèn)條件下,可使用以下C++語句獲取Halcon的文件名編碼:
HTuple codeType;
get_system("filename_encoding", &codeType);
QString strCodeType = codeType[0].S();

可以發(fā)現(xiàn)默認(rèn)的編碼是locale,此時用Halcon算子list_files獲取的文件路徑中如果包含中文,則會出現(xiàn)亂碼

解決方法:將Halcon的文件名編碼格式設(shè)置為utf8,代碼如下:
set_system("filename_encoding", "utf8");

參考鏈接:
(4條消息) VS+Qt應(yīng)用開發(fā)-使用Halcon算子實現(xiàn)從文件夾打開圖片、前后瀏覽、縮放居中顯示_羽士的博客-CSDN博客
到此這篇關(guān)于VS+Qt+Halcon 顯示圖片,實現(xiàn)鼠標(biāo)縮放、移動圖片的文章就介紹到這了,更多相關(guān)VS+Qt+Halcon鼠標(biāo)縮放、移動圖片內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言實現(xiàn)簡單學(xué)生成績管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)簡單學(xué)生成績管理系統(tǒng),具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-01-01
C語言中網(wǎng)絡(luò)地址與二進(jìn)制數(shù)之間轉(zhuǎn)換的函數(shù)小結(jié)
這篇文章主要介紹了C語言中網(wǎng)絡(luò)地址與二進(jìn)制數(shù)之間轉(zhuǎn)換的函數(shù)小結(jié),是C語言入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-09-09
C++實現(xiàn)LeetCode(123.買股票的最佳時間之三)
這篇文章主要介紹了C++實現(xiàn)LeetCode(123.買股票的最佳時間之三),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07

