【halcon】set_part 实现平移和缩放 彻悟版

2024-05-25 13:52

本文主要是介绍【halcon】set_part 实现平移和缩放 彻悟版,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

背景

之前写了一篇关于set_part 的文章 ,确实也实现了平移和缩放。平移是对的,但是缩放其实有畸变。这个问题一直都困扰着我,知道昨天连续测试了好几个小时,直到晚上11点终于完美解决。

坐标和高宽

坐标

再讲set_part 之前,我们先理一下,坐标和高宽
平时,我们通常使用 X, Y 来描述一个二维的坐标系。坐标原点一般是左下角。
而在halcon中,我们通常是使用 row 和 column来描述。
row 对应的是 Y, (row是一行行的,是Y方向走向)
column对应的是X。(colunm是一列列的,是X方向走向)
坐标原点在左上角。

高宽

高: 是 row 之间的差值(Y方向)。
宽: 是 column 之间的差值(X方向)

set_part 是 Halcon 中用于修改显示图像部分的算子。该算子允许你定义要在窗口中显示的图像的感兴趣区域(ROI),并可以根据需要进行缩放。下面我们详细解读 set_part 算子的用法及参数:

set_part 算子简单说明

1. 名称

set_part — 修改显示的图像部分。

2. 签名

set_part( : : WindowHandle, Row1, Column1, Row2, Column2 : )

3. 描述

set_part 修改在窗口中显示的图像部分。参数 (Row1, Column1) 表示图像部分的左上角,(Row2, Column2) 表示图像部分的右下角。
如果只显示图像的一部分,该部分将被缩放到整个窗口大小。可以使用 set_part_style 设置缩放插值方法。get_part 可以返回显示的图像部分的值。

除了直接设置图像部分外,还支持以下特殊模式:

  • Row1 = Column1 = Row2 = Column2 = -1:
    窗口大小被选择为图像部分,即不执行图像缩放。

  • Row1, Column1 > -1Row2 = Column2 = -1:
    选择最后显示的图像大小为图像部分,即图像可以完全显示在窗口中。如果需要,图像将被缩放。

4. 参数

  • WindowHandle (input_control) : 窗口句柄,类型为 integer

  • Row1 (input_control) : 所选图像部分左上角的行坐标,类型为 integer。默认值为 0

  • Column1 (input_control) : 所选图像部分左上角的列坐标,类型为 integer。默认值为 0

  • Row2 (input_control) : 所选图像部分右下角的行坐标,类型为 integer。默认值为 -1。限制:Row2 >= Row1Row2 == -1

  • Column2 (input_control) : 所选图像部分右下角的列坐标,类型为 integer。默认值为 -1。限制:Column2 >= Column1Column2 == -1

set_part 深度理解

从上面的说明,我们需要理解一点。set_part 的坐标参数,它的参考系是图片坐标的原点就是图片的左上角那个点! **图片动原点就跟着在变化!**理解这一点至关重要。

其实,一开始困扰的我的就是这个问题,一开始我认为,坐标系应该是以窗口为基准的,因为他是不会动的。但其实坐标系是以图片为基准的。坐标的原点就是图片的左上角那个点

再有就是,图片是显示在窗口里的,那窗口的坐标系是什么样子的呢?首先窗口本身有自己的坐标系,窗口的左上角那个点就是窗口的坐标原点。

是如何跟图片的坐标系关联的呢?很简单,看图片在哪!
如果图片的原点(图片的左上角那个点)在和窗口的左上角那个点重合。那么窗口的坐标系是和图的坐标系重合的。

图片的缩放

那现在理解一下:
set_part(WindowHandle, 0, 0, 100, 100)
这句话是说明意思?
用在窗口这个视野内,显示图片的一个部分,哪个部分?就是Rect(0, 0, 100, 100)这个部分。
更具体的理解就是:
将图片(0,0)这个点放到,窗口的左上角!,将图片100, 100这个点到窗口的右下角!仔细体会这个字!
扯,其实就是图片放大的一种差值算法。

例子1:
如果,窗口的大小是100x100,图片的大小也是 100x100。那其实图片就刚刚好放到窗口之中。

例子2:
窗口的大小是100100,图片的大小是 100100。
但此时我修改程序为: set_part(WindowHandle, 0, 0, 50, 50)
图片(0,0)这个点被固定在窗口的左上角,同时图片(50, 50) 这个点会被扯到窗口的右下角(100,100),图片就被放大了一倍。也就是说窗口大小如果不变,看到图片的区域越小,图片就会被’扯’的越大.

畸变是如何产生的

如果窗口的大小是200*100,而图片是是 50*50。
我还是这么写set_part(WindowHandle, 0, 0, 100, 100)
这样的画会发送什么?
同样,图片(0,0)这个点被固定在窗口的左上角。图片(100, 100)右下角,被扯到了窗口的右下角(200*100)。
此时,你会发现,图片的宽是之前的4倍,而高是之前的两倍.
这样宽高的放大比例不同,导致图像产生了畸变!
那要确保不发生畸变,就是要保证宽和高的放大比例相同即可!
如何扯?红色是窗口,蓝色是图片
那怎么扯,可以保证,图片不变型
很明显,窗口的宽高比为2:1 = 2, 而图片的宽高比为1:1 = 1
窗口的宽高比 > 图片宽高比。
所以, 当图片的宽高同时缓慢放大时,如果图片的高已经和窗口的高一致时,此时应该停止放大了!
放大后
这样,图片宽和高都放大了一倍,为发送形变。那此时set_part应该输入写呢?

前情提要:窗口的大小是200*100,而图片是是 50*50。

写法为:set_part(WindowHandle, 0, 0, 50, 100)
在这里插入图片描述

含义就是,图片的左上角固定在图片的窗口的左上角,当图片的(50,100)
这个点,被扯到窗口的右下角(200,100)时停止!
这里,可能有人会说了,图片就 50*50。 哪来的(50,100)?
这里就需要引入一个自定义概念(就是自己根据情景编造的):图片的延生坐标。此时,你就想象图片本身就在一个巨大的弹性巨好的画布上。画布就是图片的延时。(50,100)虽然不在图片上但是在这个画布上。我们扯画布,图片也会跟着形变。
那,这个50, 100这个点是怎么计算来的呢?这个点有几个个前提:

  1. 图片不发生形变
  2. 图片显示完全的情况下,实现最大的放大倍数。

很明显,对应上面这种情况,图片的高可以顶格显示,而宽度则需要留白。
所以:
set_part(WindowHandle, 0, 0, 50, ?)

高: 是 row 之间的差值(Y方向)。

所以图片的右下角 row值,可以扯到窗口的底部(row的最大位置。)以到达高度顶格显示的目的。
那最后一点怎么算?因为现在图片高度拉满,就是图片的高度50,那么用50再乘以窗口的宽高比,得到就是的第四个坐标的位置。

另外一种情况
在这里插入图片描述
图片的宽高比,大于窗口的宽高比。
就是图片的宽度可以顶格显示,高度留白。
假设图片的宽度是w,那么、column方向向拉满:
set_part(WindowHandle, 0, 0, ?, w)
?怎么求? w 除以 窗口的宽高比

做个小结:
首先就是需要分类讨论,窗口的宽高比和图片的宽高比哪个更大?从而判断
图片的那一条边可以顶格显示,从而计算另一个坐标的位置。
具体程序如下:

//计算缩放比例
double winWHRatio = WindowWidth.D / WindowHeight.D;
double picWHRatio = imgw.D / imgh.D;double dispWidth;
double dispHeight;//设置整个图像为显示的部分
if (picWHRatio >= winWHRatio)
{dispHeight = imgw / winWHRatio / PosEnlarge;dispWidth = imgw / PosEnlarge; HOperatorSet.SetPart(HalconWindow, 0, 0, dispHeight, dispWidth);
}
else
{dispHeight = imgh.D / PosEnlarge;dispWidth = imgh.D * winWHRatio / PosEnlarge;var offseth = row - dispHeight / 2;var offsetw = column- dispWidth / 2;HOperatorSet.SetPart(HalconWindow, 0, 0, dispHeight, dispWidth);}

不发生畸变的任意倍数放大

上面是加了一个添加的放大,就是
图片显示完全的情况下,实现最大的放大倍数。
现在,我想任意倍速放大!怎么实现?

//计算缩放比例
double winWHRatio = WindowWidth / WindowHeight;
double picWHRatio = imgw / imgh;double dispWidth;
double dispHeight;//设置整个图像为显示的部分
if (picWHRatio >= winWHRatio)
{dispHeight = imgw / winWHRatio;dispWidth = imgw; HOperatorSet.SetPart(HalconWindow, 0, 0, dispHeight, dispWidth);
}
else
{dispHeight = imgh;dispWidth = imgh * winWHRatio;HOperatorSet.SetPart(HalconWindow, 0, 0, dispHeight, dispWidth);
}

不发生畸变的任意倍数放大

上面是加了一个添加的放大,就是
图片显示完全的情况下,实现最大的放大倍数
现在,我想任意倍速放大!怎么实现?
我们,现在就定义,图片显示完全的情况下,实现最大的放大倍数。时为图像放大一个倍数!也就是自适应的做大化显示为一倍!

那如果,我要放大PosEnlarge倍,代码修改如下:

//计算缩放比例
double winWHRatio = WindowWidth / WindowHeight;
double picWHRatio = imgw / imgh;double dispWidth;
double dispHeight;//设置整个图像为显示的部分
if (picWHRatio >= winWHRatio)
{dispHeight = imgw / winWHRatio / PosEnlarge;dispWidth = imgw / PosEnlarge; HOperatorSet.SetPart(HalconWindow, 0, 0, dispHeight, dispWidth);
}
else
{dispHeight = imgh / PosEnlarge;dispWidth = imgh * winWHRatio / PosEnlarge;HOperatorSet.SetPart(HalconWindow, 0, 0, dispHeight, dispWidth);
}

改动不大,就是将之前的dispHeight 和 dispWidth 多除以了一个PosEnlarge!比如如果是放大两边就是 PosEnlarge = 2即可。
这是因为,窗口大小没变(视口不变),但是显示的区域变小,图片被拉大。
这次,不会畸变的原因是,此时在原来的基础上,同时宽高放大的一样的比例,所以不会畸变。放大的中心是(0,0)

图像的平移

SetPart 图像的缩放就讲完了,如何设置通过SetPart 进行平移?
在这里插入图片描述
首先,我们之前图片的原点和窗口左上角是重合的,此时没有平移。
如果图片向左上方平移(25,25),那么此时,窗口的左上角应该显示的是图片(25,25)这个点。那窗口的右下角的点应该随之变化 (25,25)及 row,column都加25。 这样显示的图片范围就是不变的而保证图片是仅仅发生平移,而没有形变。
那公式就是:
SetPart(HWindow, offseth, offsetw, dispHeight + offseth, dispWidth + offsetw);

这样,就能通过,offseth, offsetw 来控制 平移

平移加上缩放

现在,我有一个需求,我可以设定放大倍数,而且当我输入一个点时,需要将这个点移动到屏幕的中间!
接下来直接给出最终的代码:

    /// <summary>/// 将某个目标位置移动到中间/// </summary>public void MoveSm2Center(HObject img, HTuple row, HTuple column){HTuple win_Width, win_Height, win_Col, win_Row;HOperatorSet.GetWindowExtents(hSmart.HalconWindow, out win_Row, out win_Col, out win_Width, out win_Height);//获取窗体大小规格HTuple WindowWidth = win_Width;HTuple WindowHeight = win_Height;HTuple imgw;HTuple imgh;HOperatorSet.GetImageSize(img, out imgw, out imgh);//计算缩放比例double winWHRatio = WindowWidth.D / WindowHeight.D;double picWHRatio = imgw.D / imgh.D;double dispWidth;double dispHeight;//设置整个图像为显示的部分if (picWHRatio >= winWHRatio){dispHeight = imgw / winWHRatio / GlobalData.Instance.saveInfo.PosEnlarge;dispWidth = imgw /  GlobalData.Instance.saveInfo.PosEnlarge; HOperatorSet.SetPart(hSmart.HalconWindow, 0, 0, dispHeight, dispWidth);}else{dispHeight = imgh.D / GlobalData.Instance.saveInfo.PosEnlarge;dispWidth = imgh.D * winWHRatio / GlobalData.Instance.saveInfo.PosEnlarge;//var offseth = row - imgw / 2;//var offsetw = column - imgh / 2; var offseth = row - dispHeight / 2;var offsetw = column- dispWidth / 2;HOperatorSet.SetPart(hSmart.HalconWindow, offseth, offsetw, dispHeight + offseth, dispWidth + offsetw);}}

其中: GlobalData.Instance.saveInfo.PosEnlarge 是被定义为一个全局的变量。控制放大倍数。
HTuple row, HTuple column 传入指定的点。
这里需要主义的是:
//var offseth = row - imgw / 2;
//var offsetw = column - imgh / 2;

var offseth = row - dispHeight / 2;
var offsetw = column- dispWidth / 2;
为了移到,屏幕的中间,我用的是 dispHeight / 2 和 dispWidth / 2
而不是 图片大小的一半,或是 窗口大小的一半。

这是应为,不管是图片还是窗口,他们的一半是固定大小的。 而图片是缩放了的。
dispHeight 和 dispWidth 是图片缩放后的结果。

好了就到这里了!!!!!!

这篇关于【halcon】set_part 实现平移和缩放 彻悟版的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1001691

相关文章

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略 1. 特权模式限制2. 宿主机资源隔离3. 用户和组管理4. 权限提升控制5. SELinux配置 💖The Begin💖点点关注,收藏不迷路💖 Kubernetes的PodSecurityPolicy(PSP)是一个关键的安全特性,它在Pod创建之前实施安全策略,确保P

poj 3050 dfs + set的妙用

题意: 给一个5x5的矩阵,求由多少个由连续6个元素组成的不一样的字符的个数。 解析: dfs + set去重搞定。 代码: #include <iostream>#include <cstdio>#include <set>#include <cstdlib>#include <algorithm>#include <cstring>#include <cm

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现