本篇文章将介绍如何使用 Qt 和 Halcon 开发一个简单的图像阈值二值化检测工具。工具主要用于读取彩色图像,将其分解为单通道的RGB图像,并通过调整滑动条来动态地执行二值化处理。
功能概述
- 图像读取:从本地磁盘加载一张彩色图像。
- 通道分离:将彩色图像分解为三个独立的单通道图像(红色、绿色和蓝色通道)。
- 二值化操作:通过滑动条动态调整灰度值的范围,实现对图像的二值化处理。
- 显示图像:处理后的图像实时显示在GUI窗口中,供用户查看和调整。
开发环境准备
在开发此工具之前,您需要进行一些前期准备工作:
-
Halcon 环境配置:确保已经安装了 Halcon,并正确配置了开发环境。有疑问参考往期文章。
-
Qt/Halcon窗口显示:使用 Qt Designer 创建图形界面并绑定Halcon控件。有疑问参考往期文章。
Qt界面准备,拖拽出下面界面
- 一个图像显示区域(
graphicsView
)。 - 一个按钮用于加载图像(
pushButton
)。 - 两个个滑动条用于调整阈值范围(
horizontalSliderMin
,horizontalSliderMax
)。 - 三个单选按钮用于选择不同的通道(
红色
、绿色
、蓝色
)。
通道分离:使用 Decompose3
算子
Halcon提供了Decompose3
算子,用于将三通道的彩色图像(RGB)分解为三个独立的单通道图像:红色通道(R)、绿色通道(G)和蓝色通道(B)。因为二值化操作一般应用于灰度图像,所以在处理彩色图像时,首先需要将图像分解为单独的通道。
Decompose3
算子函数原型:
LIntExport void Decompose3(const HObject& MultiChannelImage, HObject* Image1, HObject* Image2, HObject* Image3);
参数说明:
MultiChannelImage
(const HObject&
):- 输入的多通道图像。通常是一个三通道的彩色图像(例如 RGB 图像)。这是一个包含多个颜色信息的图像对象。
Image1
(HObject*
):- 输出的第一个单通道图像。通常用于存储红色通道(R通道)或该彩色图像的其中一个通道的单通道图像。
Image2
(HObject*
):- 输出的第二个单通道图像。通常用于存储绿色通道(G通道)。
Image3
(HObject*
):- 输出的第三个单通道图像。通常用于存储蓝色通道(B通道)。
示例代码:
HObject MultiChannelImage, RedImage, GreenImage, BlueImage;// 读取彩色图像
ReadImage(&MultiChannelImage, "color_image.png");// 将彩色图像分解为红色、绿色和蓝色通道
Decompose3(MultiChannelImage, &RedImage, &GreenImage, &BlueImage);// 对红色通道进行阈值处理
HTuple hv_MinGray = 100, hv_MaxGray = 255;
Threshold(RedImage, &RedImage, hv_MinGray, hv_MaxGray);// 显示处理后的结果
DispObj(RedImage, WindowID);
DispObj(GreenImage, WindowID);
DispObj(BlueImage, WindowID);
过程:
- 读取彩色图像
color_image.png
。 - 使用
Decompose3
算子将彩色图像分解为红色通道(RedImage
)、绿色通道(GreenImage
)和蓝色通道(BlueImage
)。 - 对红色通道的图像进行阈值化操作,提取出符合灰度范围的区域。
- 在窗口中显示红色、绿色和蓝色通道图像,分别查看各个颜色通道的效果。
参数说明:
MultiChannelImage
:输入的彩色图像。Image1
、Image2
、Image3
:输出的三个单通道图像,分别对应红色、绿色和蓝色通道。
实现逻辑:
- 使用
Decompose3
算子将 RGB 图像分解为三个单通道图像。 - 根据用户选择的通道(通过单选按钮),显示相应的单通道图像。
二值化处理:使用 Threshold
算子
Halcon 的 Threshold
算子可以根据设定的灰度范围对图像进行二值化处理。此工具通过滑动条动态调整灰度值的上下限,实现对图像的实时二值化。
Threshold
算子函数原型:
void Threshold(const HObject& Image, HObject* Region, const HTuple& MinGray, const HTuple& MaxGray);
参数说明:
Image
(const HObject&
):- 这是输入的图像对象。该图像通常是灰度图像,但在某些应用中也可以是彩色图像。此图像会用于阈值化处理。
Region
(HObject*
):- 这是输出的区域对象,代表在图像中符合指定灰度范围的区域。最终结果是一个二值化的区域,可以进行进一步处理,例如连通域分析、形态学操作等。
MinGray
(const HTuple&
):- 指定最小灰度值。图像中灰度值大于或等于该值的像素将被选为区域的一部分。
MaxGray
(const HTuple&
):- 指定最大灰度值。图像中灰度值小于或等于该值的像素将被选为区域的一部分。
功能说明:
Threshold
算子通过灰度阈值处理将图像分割成两个区域:一个是符合灰度范围的区域(通过MinGray
和MaxGray
来指定),另一个是所有其他区域。这个操作通过以下步骤实现:
- 筛选灰度值:
- 算子会对输入图像中的每个像素进行遍历,判断其灰度值是否在
MinGray
和MaxGray
之间。符合条件的像素点会被保留下来,形成感兴趣区域(Region)。
- 算子会对输入图像中的每个像素进行遍历,判断其灰度值是否在
- 输出区域:
- 最终,符合灰度值范围的区域会被保存在
Region
中,这些区域可以用于后续的图像分析和处理。
- 最终,符合灰度值范围的区域会被保存在
使用场景:
- 二值化:当你只关心图像中某些特定灰度值范围的像素时,这个算子是非常有用的。比如,提取某个物体或特征区域。
- 噪声去除:通过设置合适的阈值范围,可以去除背景噪声或其他不需要的区域,只保留有意义的部分。
- 边缘检测:有时可以通过阈值化来帮助边缘检测操作,提取图像中的轮廓。
示例代码:
HObject Image, Region;
HTuple hv_MinGray, hv_MaxGray;// 读取图像
ReadImage(&Image, "example_image.png");// 设置阈值范围
hv_MinGray = 100; // 最小灰度值
hv_MaxGray = 200; // 最大灰度值// 执行阈值操作
Threshold(Image, &Region, hv_MinGray, hv_MaxGray);// 显示结果
DispObj(Region, WindowID);
过程:
- 读取图像
example_image.png
。 - 设置最小灰度值为100,最大灰度值为200。
- 使用
Threshold
算子将图像中灰度值在100到200范围内的区域提取出来,生成Region
。 - 在窗口中显示结果区域。
注意事项:
MinGray
和MaxGray
的设置要根据实际的图像内容和需求来调整。如果这两个值设置得不合适,可能会得到过多或过少的区域,导致不准确的分割。- 该算子适用于灰度图像,因此输入的图像应当为灰度图像或需要转换为灰度图像。
Qt与Halcon代码实现
接下来,我们将展示具体的代码实现,首先是 .h
文件定义,接着是 .cpp
文件的实现。
.h 文件(mainwindow.h
)
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include "HalconCpp.h"QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();void displayImage(const HalconCpp::HObject &hv_dispimage);void thresholdImage();private slots:void on_pushButton_clicked();void on_horizontalSliderMin_sliderMoved(int position);void on_horizontalSliderMax_sliderMoved(int position);private:Ui::MainWindow *ui;HalconCpp::HTuple hv_window;HalconCpp::HObject hv_orcImage, hv_grayImage;
};
#endif // MAINWINDOW_H
.cpp 文件(mainwindow.cpp
)
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "HalconCpp.h"
#include <QDebug>
using namespace HalconCpp;MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);// 设置窗口属性HalconCpp::OpenWindow(0, 0, 1000, 800, static_cast<Hlong>(ui->graphicsView->winId()), "", "", &hv_window);HalconCpp::SetColored(hv_window, 12);HalconCpp::SetHcppInterfaceStringEncodingIsUtf8(true);// 通道分离 - Rconnect(ui->radioButtonR, &QRadioButton::clicked, [=]() {HalconCpp::HObject hv_ImageR, hv_ImageG, hv_ImageB;HalconCpp::Decompose3(hv_orcImage, &hv_grayImage, &hv_ImageG, &hv_ImageB);displayImage(hv_grayImage);});// 通道分离 - Gconnect(ui->radioButtonG, &QRadioButton::clicked, [=]() {HalconCpp::HObject hv_ImageR, hv_ImageG, hv_ImageB;HalconCpp::Decompose3(hv_orcImage, &hv_ImageR, &hv_grayImage, &hv_ImageB);displayImage(hv_grayImage);});// 通道分离 - Bconnect(ui->radioButtonB, &QRadioButton::clicked, [=]() {HalconCpp::HObject hv_ImageR, hv_ImageG, hv_ImageB;HalconCpp::Decompose3(hv_orcImage, &hv_ImageR, &hv_ImageG, &hv_grayImage);displayImage(hv_grayImage);});
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::displayImage(const HalconCpp::HObject &hv_dispimage)
{HTuple hv_width, hv_height;HalconCpp::GetImageSize(hv_dispimage, &hv_width, &hv_height);HalconCpp::SetPart(hv_window, 0, 0, hv_height - 1, hv_width - 1);HalconCpp::DispObj(hv_dispimage, hv_window);
}void MainWindow::thresholdImage()
{HalconCpp::HObject hv_Region;HalconCpp::Threshold(hv_grayImage, &hv_Region, ui->horizontalSliderMin->value(), ui->horizontalSliderMax->value());displayImage(hv_grayImage);HalconCpp::DispObj(hv_Region, hv_window);
}void MainWindow::on_pushButton_clicked()
{ReadImage(&hv_orcImage, "1.jpg");HTuple hv_width, hv_height;HalconCpp::GetImageSize(hv_orcImage, &hv_width, &hv_height);HalconCpp::SetPart(hv_window, 0, 0, hv_height - 1, hv_width - 1);HalconCpp::DispObj(hv_orcImage, hv_window);
}void MainWindow::on_horizontalSliderMin_sliderMoved(int position)
{int maxPosition = ui->horizontalSliderMax->value();if (position > maxPosition) {ui->horizontalSliderMax->setValue(position);}thresholdImage();
}void MainWindow::on_horizontalSliderMax_sliderMoved(int position)
{int minPosition = ui->horizontalSliderMin->value();if (position < minPosition) {ui->horizontalSliderMin->setValue(position);}thresholdImage();
}