阅读 259

VS+Qt+Halcon——显示图片,实现鼠标缩放、移动图片

摘要

本篇博文记录一下,用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_OBJECTpublic:
    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.0Mylabel::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_OBJECTpublic:
    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");

三,项目打包


需要注意一点的是:对于halcon库的需要

服务器评测 http://www.cncsto.com/ 

服务器测评 http://www.cncsto.com/ 

站长资源 https://www.cscnn.com/ 

小鱼号 https://www.237fa.com/ 

 


文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐