Qt 联合Halcon视觉框架(1)

效果

请添加图片描述

QHalconWind 类

// HALCON/Qt pattern matching and measure example
//
// (c) 2004-2017 MVTec Software GmbH

// QHalconWindow.h : Class used for opening HALCON windows in Qt
//

#include <QWidget>
#include <QPainter>
#include <QScopedPointer>

#ifndef __APPLE__
#  include "HalconCpp.h"
#else
#  ifndef HC_LARGE_IMAGES
#    include <HALCONCpp/HalconCpp.h>
#  else
#    include <HALCONCppxl/HalconCpp.h>
#  endif
#endif


class QHalconWindow : public QWidget
{
  Q_OBJECT

public:
    // 构造函数,初始化一个新的 HALCON 窗口。接受一个可选的父窗口部件、宽度和高度参数。
    // parent 参数允许将这个窗口作为另一个窗口的小部件嵌入。
    // Width 和 Height 参数用于设置窗口的初始大小。
    QHalconWindow(QWidget *parent = nullptr, long Width = 0, long Height = 0);

    // 提供对 HALCON 图形缓冲区的访问。返回指向 HALCON HWindow 对象的指针,
    // 允许外部代码与 HALCON 图像处理环境交互。
    HalconCpp::HWindow* GetHalconBuffer(void) { return halconBuffer.data(); }

protected:
    // 当窗口大小改变时被调用。这里可以处理窗口大小变化后的逻辑,
    // 例如调整 HALCON 缓冲区的大小。
    void resizeEvent(QResizeEvent* event) override;

    // 当需要更新窗口内容时被调用。在这里实现实际的绘制逻辑,
    // 比如从 HALCON 缓冲区获取图像并绘制到窗口上。
    void paintEvent(QPaintEvent* event) override;

    // 鼠标移动事件处理函数,响应用户的鼠标移动操作。
    void mouseMoveEvent(QMouseEvent* event) override;

    // 鼠标按下事件处理函数,响应用户按下鼠标按键的操作。
    void mousePressEvent(QMouseEvent* event) override;

    // 鼠标释放事件处理函数,响应用户释放鼠标按键的操作。
    void mouseReleaseEvent(QMouseEvent* event) override;

    // 鼠标双击事件处理函数,响应用户的鼠标双击操作。
    void mouseDoubleClickEvent(QMouseEvent* event) override;

    // 鼠标滚轮事件处理函数,响应用户的鼠标滚轮滚动操作。
    void wheelEvent(QWheelEvent* event) override;

private:
    // 获取 HALCON 窗口中的某个区域坐标
    void GetPartFloat(double* row1, double* col1, double* row2, double* col2);

    // 设置 HALCON 窗口中的某个区域坐标
    void SetPartFloat(double row1, double col1, double row2, double col2);

    // 智能指针,管理 HALCON 的 HWindow 对象,确保其生命周期与 QHalconWindow 实例一致。
    // halconBuffer 是 HALCON 图像处理的图形缓冲区。
    QScopedPointer<HalconCpp::HWindow> halconBuffer;

    // 成员变量,用于保存最近一次鼠标位置和 HALCON 窗口的某些区域坐标。
    // 可能在处理鼠标事件或更新显示时使用这些值。
    QPoint lastMousePos;
    double lastRow1, lastCol1, lastRow2, lastCol2;
};

回调函数刷新窗口

Herror __stdcall ContentUpdateCallback(void *context)
{
  // 定义一个名为 ContentUpdateCallback 的回调函数,
  // 使用 Windows API 标准调用约定 (__stdcall)。
  // 函数接收一个指向用户定义数据的指针 (void *context),该数据将被用于回调操作。

  // 注释解释了这个回调会在何时被调用:
  // 当缓冲区刷新时会调用此回调;如果启用了自动刷新(默认情况下是启用的),则每次图形缓冲区更改后都会调用。

  QHalconWindow* hwindow = (QHalconWindow*)context;

  // 将传入的 context 参数强制转换为 QHalconWindow 类型的指针,
  // 并赋值给局部变量 hwindow。这假设传递给回调的上下文是指向 QHalconWindow 实例的指针。

  // schedule redraw in Qt thread
  hwindow->update();

  // 调用 hwindow 指向的对象的 update() 方法来安排重绘。
  // 这个方法不会立即导致窗口重绘,而是告诉 Qt 应用程序在下一次事件循环迭代时重绘窗口。

  return H_MSG_OK;
  // 返回 H_MSG_OK 值,表示回调成功完成。
  // H_MSG_OK 可能是一个预定义的宏或常量,用来表示消息处理状态。
}

构造函数

QHalconWindow::QHalconWindow(QWidget *parent, long Width, long Height)
        : QWidget(parent), lastMousePos(-1, -1)
{
    // 显示窗口。这确保窗口在创建后立即可见。
    show();

    // 设置窗口的大小为指定的宽度和高度。如果 Width 和 Height 为 0,则使用默认大小。
    resize(Width, Height);


    //打开图形窗口
    halconBuffer.reset(new HalconCpp::HWindow(0, 0, 100, 100, 0, "buffer", ""));

    // 启用图形堆栈功能,使得图像和区域在缩放或调整窗口大小后仍然保持不变。
    halconBuffer->SetWindowParam("graphics_stack", "true");

    // 关闭自动刷新(flush),启用显式刷新模式。
    halconBuffer->SetWindowParam("flush", "false");

    // 注册一个回调函数 ContentUpdateCallback,用于响应缓冲区内容更新事件。
    // 第二个参数 this 表示当前对象实例作为回调函数的上下文,允许回调函数访问 QHalconWindow 的成员。
    //刷新窗口
    halconBuffer->SetContentUpdateCallback((void*)&ContentUpdateCallback, this);
}

保证窗口大小和Halcon 窗口大小一致

// 当 QHalconWindow 小部件的大小发生变化时调整 HALCON 窗口的大小。
void QHalconWindow::resizeEvent(QResizeEvent* event)
{
  
  Q_UNUSED(event);

  //设置窗口的坐标和宽高
  halconBuffer->SetWindowExtents(0, 0, width(), height());

  // 触发缓冲区刷新,以确保 HALCON 窗口内容根据新的尺寸重新绘制。
  halconBuffer->FlushBuffer();
}

绘制图片

void QHalconWindow::paintEvent(QPaintEvent *event)
{
  // 使用命名空间以避免每次调用 HALCON 函数时都需要前缀。
  using namespace HalconCpp;

  Q_UNUSED(event);
 
  HString type;
  Hlong width, height;

  // 获取 HALCON 缓冲区的内容。
 	// 将图片加载进窗口
  HImage image = halconBuffer->DumpWindowImage();

  // 将 HALCON 图像转换为适合 Qt 使用的格式。
  // InterleaveChannels() 方法将图像通道重新排列为 ARGB 格式,并确保与 Qt 的颜色匹配。
  HImage imageInterleaved = image.InterleaveChannels("argb", "match", 0);

  // 获取转换后图像的原始数据指针。
  // GetImagePointer1() 返回指向图像数据的指针,并提供有关图像类型和尺寸的信息。
  unsigned char* pointer = (unsigned char*)imageInterleaved.GetImagePointer1(&type, &width, &height);

  // 使用原始图像数据创建一个 QImage 对象。
  // 注意:宽度除以 4 是因为每个像素包含 4 个字节(ARGB),而 QImage::Format_RGB32 每个像素占用 4 字节。
  QImage qimage(pointer, width / 4, height, QImage::Format_RGB32);

  // 创建 QPainter 对象并开始绘制。
  // 将 QImage 绘制到小部件上,从左上角 (0, 0) 开始。
  QPainter painter(this);
  painter.drawImage(QPoint(0, 0), qimage);
}

获取坐标点

void QHalconWindow::GetPartFloat(double *row1, double *col1, double *row2, double *col2)
{
  // 为了从 get_part 获取浮点值,使用 HTuple 参数。
  // HTuple 是 HALCON 中用于处理多个数值或不同类型数据的类,
  // 它可以存储和操作任意数量的元素,并且支持多种数据类型。

  HalconCpp::HTuple trow1, tcol1, trow2, tcol2;

  // 调用 halconBuffer 的 GetPart 方法来获取当前窗口显示区域的边界坐标。
  // 这些坐标将被存储在 HTuple 对象中。
  halconBuffer->GetPart(&trow1, &tcol1, &trow2, &tcol2);

  // 将 HTuple 对象中的第一个元素(即浮点数)转换为 double 类型,并赋值给输出参数。
  // .D() 方法用于将 HTuple 中的第一个元素转换为双精度浮点数。
  *row1 = trow1.D();
  *col1 = tcol1.D();
  *row2 = trow2.D();
  *col2 = tcol2.D();
}

设置坐标点

void QHalconWindow::SetPartFloat(double row1, double col1, double row2, double col2)
{
  // 将 double 类型的值转换为 HTuple。如果不进行转换,将会调用 SetPart 的整数版本。
  // 使用 HTuple 确保可以传递浮点数值,从而实现平滑的移动和缩放,即使在放大时也能保持精度。

  // 调用 halconBuffer 的 SetPart 方法来设置 HALCON 窗口显示区域的边界坐标。
  // 通过将 double 参数包装在 HTuple 中,确保 HALCON 接收到的是浮点数而不是整数。
  // 这样可以保证窗口边界坐标的精确性,支持更加精细和平滑的操作。
  halconBuffer->SetPart(
      HalconCpp::HTuple(row1),  // 左上角行坐标 (row1)
      HalconCpp::HTuple(col1),  // 左上角列坐标 (col1)
      HalconCpp::HTuple(row2),  // 右下角行坐标 (row2)
      HalconCpp::HTuple(col2)   // 右下角列坐标 (col2)
  );
}

鼠标拖动图片

void QHalconWindow::mouseMoveEvent(QMouseEvent *event)
{
  // 检查是否按下了鼠标左键,并且 lastMousePos 已经被初始化(即 x() 不等于 -1)。
  if ((event->buttons() == Qt::LeftButton) && lastMousePos.x() != -1)
  {
    // 计算鼠标移动的距离(delta),从上一次的位置到当前事件位置。
    // 使用全局坐标系以确保即使窗口移动,计算仍然准确。
    QPoint delta = lastMousePos - event->globalPos();

    // 根据当前窗口的缩放比例调整 delta 的大小。
    // scalex 和 scaley 分别是水平和垂直方向上的缩放因子,
    // 它们基于图像的显示区域与窗口尺寸的比例。
    double scalex = (lastCol2 - lastCol1 + 1) / (double)width();
    double scaley = (lastRow2 - lastRow1 + 1) / (double)height();

    try
    {
      // 设置新的可见区域。根据鼠标移动的距离(delta)调整显示区域的边界坐标。
      // 这里使用了缩放因子来确保平移量与当前缩放级别匹配。
      SetPartFloat(lastRow1 + (delta.y() * scaley),
                   lastCol1 + (delta.x() * scalex),
                   lastRow2 + (delta.y() * scaley),
                   lastCol2 + (delta.x() * scalex));

      // 触发缓冲区刷新,以更新 HALCON 窗口的内容。
      // 这将导致重新绘制,显示新的可见区域。
      halconBuffer->FlushBuffer();
    }
    catch (HalconCpp::HOperatorException &e)
    {
      // 如果设置新可见区域失败(例如,图像部分移出窗口),捕获异常并忽略错误。
      // 这种情况可能发生在用户尝试将图像拖动到窗口外时。
      // 可选:可以在这里添加日志记录或用户通知。
      // qDebug() << "Failed to set new visible part: " << e.what();
    }

    // 更新 lastMousePos 为当前事件的位置,以便下次计算 delta。
    lastMousePos = event->globalPos();
  }
}

鼠标按下

void QHalconWindow::mousePressEvent(QMouseEvent *event)
{
  // 保存当前鼠标位置和图像显示区域。
  // 这些信息将在后续的鼠标移动事件中用于计算平移量。

  // 获取当前 HALCON 窗口显示区域的边界坐标,并保存到成员变量中。
  // lastRow1, lastCol1 是显示区域的左上角坐标,
  // lastRow2, lastCol2 是显示区域的右下角坐标。
  GetPartFloat(&lastRow1, &lastCol1, &lastRow2, &lastCol2);

  // 记录当前鼠标按下时的全局位置(屏幕坐标)。
  // 这个位置将用于后续的鼠标移动事件中计算鼠标移动的距离。
  lastMousePos = event->globalPos();
}

鼠标抬起

void QHalconWindow::mouseReleaseEvent(QMouseEvent *event)
{
  // 使用 Q_UNUSED 宏来避免编译器对未使用的参数发出警告。
  // 在这个方法中,event 参数实际上没有被使用。
  Q_UNUSED(event);

  // 取消设置参考鼠标位置。
  // 将 lastMousePos 设置为一个无效值 (-1, -1),表示不再有有效的参考点。
  // 这样可以确保在下次鼠标按下事件之前,不会有旧的鼠标位置影响新的拖动操作。
  lastMousePos = QPoint(-1, -1);
}

鼠标双击

void QHalconWindow::mouseDoubleClickEvent(QMouseEvent *event)
{
  // 使用 Q_UNUSED 宏来避免编译器对未使用的参数发出警告。
  // 在这个方法中,event 参数实际上没有被使用。
  Q_UNUSED(event);

  // 检查是否是左键双击事件。
  if (event->buttons() == Qt::LeftButton)
  {
    // 重置图像显示区域为默认值。
    // SetPart 的参数 (0, 0, -1, -1) 表示将显示区域设置为整个图像,
    // 即取消任何缩放或平移效果,恢复到原始视图。
    halconBuffer->SetPart(0, 0, -1, -1);

    // 刷新 HALCON 缓冲区以应用更改并更新显示。
    // 这会触发窗口内容的重新绘制,显示重置后的图像。
    halconBuffer->FlushBuffer();
  }
}

滚轮放大缩小图片

void QHalconWindow::wheelEvent(QWheelEvent *event)
{
  // event->delta() 是 120 的倍数。较大的倍数表示用户滚动了多个刻度。
  int num_notch = std::abs(event->delta()) / 120;

  // 计算缩放因子。每次滚轮向上滚动时(正 delta),图像放大;向下滚动时(负 delta),图像缩小。
  double factor = (event->delta() > 0) ? std::sqrt(2.0) : 1.0 / std::sqrt(2.0);

  // 如果用户滚动了多个刻度,调整缩放因子以匹配滚动次数。
  while (num_notch > 1)
  {
    factor = factor * ((event->delta() > 0) ? std::sqrt(2.0) : 1.0 / std::sqrt(2.0));
    num_notch--;
  }

  // 获取缩放中心点。将鼠标指针位置从窗口坐标转换为图像坐标。
  double centerRow, centerCol;
  halconBuffer->ConvertCoordinatesWindowToImage(event->y(), event->x(), &centerRow, &centerCol);

  // 获取当前图像显示区域的边界坐标。
  double row1, col1, row2, col2;
  GetPartFloat(&row1, &col1, &row2, &col2);

  // 计算相对于中心点的四个边界的距离。
  double left = centerRow - row1;
  double right = row2 - centerRow;
  double top = centerCol - col1;
  double bottom = col2 - centerCol;

  // 根据缩放因子调整新的显示区域边界。
  double newRow1 = centerRow - left * factor;
  double newRow2 = centerRow + right * factor;
  double newCol1 = centerCol - top * factor;
  double newCol2 = centerCol + bottom * factor;

  try
  {
    // 设置新的显示区域。
    SetPartFloat(newRow1, newCol1, newRow2, newCol2);

    // 刷新 HALCON 缓冲区以应用更改并更新显示。
    halconBuffer->FlushBuffer();
  }
  catch (HalconCpp::HOperatorException &e)
  {
    // 如果设置新显示区域失败(例如,部分区域过小或过大),捕获异常并忽略错误。
    // 这种情况可能发生在用户尝试过度缩放时。
    // 可选:可以在这里添加日志记录或用户通知。
    // qDebug() << "Failed to set new visible part: " << e.what();
  }
}
QTQt)是一种跨平台的C++图形用户界面(GUI)应用程序开发框架。它是一种开源且功能强大的框架,提供了丰富的组件和工具,可以高效地开发各种类型的应用程序。 Halcon是一种非常强大的机器视觉开发工具包,提供了多种功能和算法,用于图像处理、分析和识别。它支持各种操作系统和编程语言,并提供了易于使用的图形界面以及丰富的示例和文档。 QT Halcon视觉框架结合了QTHalcon两个框架的优势。它使用QT作为界面开发的基础,使用Halcon进行图像处理和分析。这样的组合使得开发者可以利用QT的丰富功能和易用性来构建用户界面,并利用Halcon强大的视觉处理功能来实现各种图像分析和识别任务。 QT Halcon视觉框架的优势有以下几点: 1. 强大的视觉处理功能:Halcon提供了多种高级的图像处理和分析算法,可以满足各种复杂的应用需求。通过与QT的结合,可以实现图像处理与界面交互的无缝集成。 2. 跨平台支持:QT本身就是一个跨平台的框架,可以在多个操作系统上运行,而Halcon也支持多种操作系统。这使得QT Halcon视觉框架能够轻松地在不同平台上开发和部署应用程序。 3. 开发效率高:QT提供了丰富的组件和工具,可以快速地构建用户界面,而Halcon提供了丰富的示例和文档,能够帮助开发者快速上手。通过使用QT Halcon视觉框架开发者可以以较少的代码实现复杂的视觉处理任务。 4. 界面友好:QT的界面设计非常美观和易于使用,可以提供良好的用户体验。通过QT Halcon视觉框架开发者可以创建功能强大且界面友好的图像处理应用程序。 综上所述,QT Halcon视觉框架是一种强大而高效的图像处理开发工具,通过结合QTHalcon的优势,可以实现高级的图像处理和分析任务,并提供良好的用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值