【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 / 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 是图片缩放后的结果。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/645117.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C语言实现三子棋游戏

目录 一.三子棋游戏分析和设计 二.文件结构设计 三.代码实现 1.先打印菜单&#xff0c;定义menu函数。 2.棋盘初始化 3.下棋 玩家下棋&#xff1a; 电脑下棋&#xff1a; 4判断输赢 判断平局&#xff1a; 四、完整代码 test.c game.h game.c 《三子棋》是一款古老…

【找出满足差值条件的下标 I】python

目录 暴力题解 优化&#xff1a;滑动窗口维护大小值 暴力题解 class Solution:def findIndices(self, nums: List[int], indexDifference: int, valueDifference: int) -> List[int]:nlen(nums)for i in range(n):for j in range(n-1,-1,-1):if abs(i-j)>indexDiffere…

python使用base加密解密

原理 base编码是一种加密解密措施&#xff0c;目前常用的有base16、base32和base64。其大致原理比较简单。 以base64为例&#xff0c;base64加密后共有64中字符。其加密过程是编码后将每3个字节作为一组&#xff0c;这样每组就有3*824位。将每6位作为一个单位进行编码&#xf…

Windows平台C#版RTSP转RTMP直播推送定制版

技术背景 前几年我们发布了C版的多路RTMP/RTSP转RTMP转发官方定制版。在秉承低延迟、灵活稳定、低资源占用的前提下&#xff0c;客户无需关注开发细节&#xff0c;只需图形化配置转发等各类参数&#xff0c;实现产品快速上线目的。 如监控类摄像机、NVR等&#xff0c;通过厂商…

经典链表题-链表回文结构

&#x1f389;&#x1f389;&#x1f389;欢迎莅临我的博客空间&#xff0c;我是池央&#xff0c;一个对C和数据结构怀有无限热忱的探索者。&#x1f64c; &#x1f338;&#x1f338;&#x1f338;这里是我分享C/C编程、数据结构应用的乐园✨ &#x1f388;&#x1f388;&…

C#基础语言

​​​​ 目录 一个c# 程序主要包括以下部分&#xff1a;​​​​​​​ 标识符 C# 关键字 C# 数据类型 值类型&#xff08;Value types&#xff09; 引用类型&#xff08;Reference types&#xff09; 对象&#xff08;Object&#xff09;类型 动态&#xff08;Dynam…

迅睿 CMS 中开启【ionCube 扩展】的方法

有时候我们想要某种功能时会到迅睿 CMS 插件市场中找现有的插件&#xff0c;但会有些担心插件是否适合自己的需求。于是迅睿 CMS 考虑到这一层推出了【申请试用】&#xff0c;可以让用户申请试用 30 天&#xff0c;不过试用是有条件的&#xff0c;条件如下&#xff1a; php 版…

03. Spring 事务管理

文章目录 1. Spring 事务管理简介2. Transactional 注解属性信息3. Transactional 简单使用4. Transactional 使用注意事项4.1 正确指定事务回滚的异常类型4.1.1 Java 异常继承体系 4.2 Transactional 注解应用在 public 方法或类上才有效4.3 正确设置 Transactional 的 propag…

解决vue3项目vite打包忽略.vue扩展名

项目打包时报could not relolve “...”&#xff0c;因为vite已不再默认忽略.vue扩展名。 解决方法如下&#xff1a; 在vite.config.js中配置vite使其忽略 .vue 扩展名&#xff08;不建议忽略&#xff09; 注意&#xff1a;即使忽略了.vue文件&#xff0c;在实际写的时候也要加…

【CTF Web】CTFShow web7 Writeup(SQL注入+PHP+进制转换)

web7 1 阿呆得到最高指示&#xff0c;如果还出问题&#xff0c;就卷铺盖滚蛋&#xff0c;阿呆心在流血。 解法 注意到&#xff1a; <!-- flag in id 1000 -->拦截很多种字符&#xff0c;连 select 也不给用了。 if(preg_match("/\|\"|or|\||\-|\\\|\/|\\*|\…

Spring MVC+mybatis 项目入门:旅游网(一)项目创建与准备

个人博客&#xff1a;Spring MVCmybatis 项目入门:旅游网&#xff08;一&#xff09;项目创建与准备 | iwtss blog 先看这个&#xff01; 这是18年的文章&#xff0c;回收站里恢复的&#xff0c;现阶段看基本是没有参考意义的&#xff0c;技术老旧脱离时代&#xff08;2024年辣…

使用不同的编译器编译 Skia,性能差距居然这么大

Skia 是一个开源的 2D 图形库&#xff0c;提供路径、文本、图像和渲染等图形处理功能。它最初由 Skia Inc. 开发&#xff0c;后来被 Google 收购&#xff0c;并用在多个 Google 的产品中&#xff0c;包括 Chrome 浏览器和 Android 操作系统中。从事 Android 系统开发的同学应该…

Science 基于尖峰时序编码的模拟神经触觉系统,可实现动态对象分类

快速处理和有效利用手与物体交互过程中产生的动态触觉信号&#xff08;例如触摸和抓握&#xff09;对于触觉探索和灵巧的物体操作至关重要。将电子皮肤&#xff08;e-skins&#xff09;推进到模仿自然触觉的水平&#xff0c;是恢复截肢者和瘫痪患者丧失的功能的可行解决方案&am…

北核论文完美复现:自适应t分布与动态边界策略改进的算术优化算法

声明&#xff1a;文章是从本人公众号中复制而来&#xff0c;因此&#xff0c;想最新最快了解各类智能优化算法及其改进的朋友&#xff0c;可关注我的公众号&#xff1a;强盛机器学习&#xff0c;不定期会有很多免费代码分享~ 目录 原始算术优化算法 改进点1&#xff1a;引入…

深入探索MySQL SELECT查询:从基础到高级,解锁数据宝藏的密钥

系列文章目录 更新ing... MySQL操作全攻略&#xff1a;库、表、数据、事务全面指南深入探索MySQL SELECT查询&#xff1a;从基础到高级&#xff0c;解锁数据宝藏的密钥MySQL SELECT查询实战&#xff1a;练习题精选&#xff0c;提升你的数据库查询技能PyMySQL&#xff1a;连接P…

【电路笔记】-巴特沃斯滤波器设计

巴特沃斯滤波器设计 文章目录 巴特沃斯滤波器设计1、概述2、Decades和Octaves3、低通巴特沃斯滤波器设计4、滤波器设计 – 巴特沃斯低通5、三阶巴特沃斯低通滤波器在之前的滤波器教程中,我们研究了简单的一阶型低通和高通滤波器,这些滤波器的 RC 滤波器电路设计中仅包含一个电…

Ant design vue的表格双击编辑功能(即双击开始编辑并自动获得焦点,失去焦点时完成编辑)

本文基于Ant Design Vue官方网站的表格&#xff08;可编辑单元格&#xff09;&#xff08;表格 Table - Ant Design Vue (antdv.com))中的样板代码获得双击编辑且获得焦点、失去焦点时完成编辑的功能。 要点&#xff1a; &#xff08;1&#xff09;双击时候实现编辑&#xff…

spark实战:实现分区内求最大值,分区间求和以及获取日志文件固定日期的请求路径

spark实战&#xff1a;实现分区内求最大值&#xff0c;分区间求和以及获取日志文件固定日期的请求路径 Apache Spark是一个广泛使用的开源大数据处理框架&#xff0c;以其快速、易用和灵活的特点而受到开发者的青睐。在本文中&#xff0c;我们将通过两个具体的编程任务来展示S…

在CentOS7上安装Oracle11

一、概述 Oracle有两种安装方式&#xff0c;桌面安装和静默安装。这里我采用桌面安装的方式。 不得不说&#xff0c;Oracle真的是我目前为止安装过的最麻烦的软件没有之一&#xff0c;比K8S还麻烦&#xff0c;Oracle&#xff0c;真有你的&#xff01;废话不多说&#xff0c;臭…

重学java 45.多线程 下 总结 定时器_Timer

人开始反向思考 —— 24.5.26 定时器_Timer 1.概述:定时器 2.构造: Timer() 3.方法: void schedule(TimerTask task, Date firstTime, long period) task:抽象类,是Runnable的实现类 firstTime:从什么时间开始执行 period:每隔多长时间执行一次…