Python OpenCV:利用滚动条移动图片,利用鼠标缩放图片

刺骨的言语ヽ痛彻心扉 2022-03-24 17:10 1503阅读 0赞

Python OpenCV:利用滚动条移动图片,利用鼠标缩放图片

  • 一、实现目标
  • 二、实现背景
  • 三、实现方法
  • 四、运行环境
  • 五、运行代码
  • 六、运行结果
  • 七、不足
  • 八、参考

一、实现目标

  在OpenCV显示比窗口更大的图片,可通过右侧的垂直滚动条和底部的水平滚动条移动图片来显示全图。
在这里插入图片描述

二、实现背景

  在OpenCV中,虽然有cv2.getTrackbarPos() 函数,但其作用主要是用作动态调节参数的控件,更准确名称应为滑动条,而非作为滚动条控件使用。经查询发现OpenCV并没有滚动条控件,其对于大于显示窗口的图片来说,OpenCv只能显示原比例图片的部分内容或者缩放后的图片,而无法显示原比例图片的全部内容

三、实现方法

  1. 自己在OpenCv显示窗口画出滚动条,并通过鼠标事件实现其功能(在此详讲的,如果你一定要使用OpenCV界面的话);
  2. 使用其它界面工具如QT等的滚动条控件来实现图片(此方法另谈)。

四、运行环境

  1. 在windows下已安装Python(必须的,我使用的是python3.7);
  2. 安装PyCharm(方便编程调试)
  3. 安装opencv-python(在python下安装配置OpenCV)

五、运行代码

  1. import cv2
  2. #鼠标事件
  3. def mouse(event, x, y, flags, param):
  4. global flag, horizontal, vertical, flag_hor, flag_ver, dx, dy, sx, sy, dst, x1, y1, x2, y2, x3, y3, f1, f2
  5. global zoom, scroll_har, scroll_var, img_w, img_h, img, dst1, win_w, win_h, show_w, show_h
  6. if event == cv2.EVENT_LBUTTONDOWN: # 左键点击
  7. if flag == 0:
  8. if horizontal and 0 < x < win_w and win_h - scroll_w < y < win_h:
  9. flag_hor = 1 # 鼠标在水平滚动条上
  10. elif vertical and win_w - scroll_w < x < win_w and 0 < y < win_h:
  11. flag_ver = 1 # 鼠标在垂直滚动条上
  12. if flag_hor or flag_ver:
  13. flag = 1 # 进行滚动条垂直
  14. x1, y1, x2, y2, x3, y3 = x, y, dx, dy, sx, sy # 使鼠标移动距离都是相对于初始滚动条点击位置,而不是相对于上一位置
  15. elif event == cv2.EVENT_MOUSEMOVE and (flags & cv2.EVENT_FLAG_LBUTTON): # 按住左键拖曳
  16. if flag == 1:
  17. if flag_hor:
  18. w = (x - x1)/2 # 移动宽度
  19. dx = x2 + w * f1 # 原图x
  20. if dx < 0: # 位置矫正
  21. dx = 0
  22. elif dx > img_w - show_w:
  23. dx = img_w - show_w
  24. sx = x3 + w # 滚动条x
  25. if sx < 0: # 位置矫正
  26. sx = 0
  27. elif sx > win_w - scroll_har:
  28. sx = win_w - scroll_har
  29. if flag_ver:
  30. h = y - y1 # 移动高度
  31. dy = y2 + h * f2 # 原图y
  32. if dy < 0: # 位置矫正
  33. dy = 0
  34. elif dy > img_h - show_h:
  35. dy = img_h - show_h
  36. sy = y3 + h # 滚动条y
  37. if sy < 0: # 位置矫正
  38. sy = 0
  39. elif sy > win_h - scroll_var:
  40. sy = win_h - scroll_var
  41. dx, dy = int(dx), int(dy)
  42. img1 = img[dy:dy + show_h, dx:dx + show_w] # 截取显示图片
  43. print(dy, dy + show_h, dx, dx + show_w)
  44. dst = img1.copy()
  45. elif event == cv2.EVENT_LBUTTONUP: # 左键释放
  46. flag, flag_hor, flag_ver = 0, 0, 0
  47. x1, y1, x2, y2, x3, y3 = 0, 0, 0, 0, 0, 0
  48. elif event == cv2.EVENT_MOUSEWHEEL: # 滚轮
  49. if flags > 0: # 滚轮上移
  50. zoom += wheel_step
  51. if zoom > 1 + wheel_step * 20: # 缩放倍数调整
  52. zoom = 1 + wheel_step * 20
  53. else: # 滚轮下移
  54. zoom -= wheel_step
  55. if zoom < wheel_step: # 缩放倍数调整
  56. zoom = wheel_step
  57. zoom = round(zoom, 2) # 取2位有效数字
  58. img_w, img_h = int(img_original_w * zoom), int(img_original_h * zoom) # 缩放都是相对原图,而非迭代
  59. img_zoom = cv2.resize(img_original, (img_w, img_h), interpolation=cv2.INTER_AREA)
  60. horizontal, vertical = 0, 0
  61. if img_h <= win_h and img_w <= win_w:
  62. dst1 = img_zoom
  63. cv2.resizeWindow("img", img_w, img_h)
  64. scroll_har, scroll_var = 0, 0
  65. f1, f2 = 0, 0
  66. else:
  67. if img_w > win_w and img_h > win_h:
  68. horizontal, vertical = 1, 1
  69. scroll_har, scroll_var = win_w * show_w / img_w, win_h * show_h / img_h
  70. f1, f2 = (img_w - show_w) / (win_w - scroll_har), (img_h - show_h) / (win_h - scroll_var)
  71. elif img_w > win_w and img_h <= win_h:
  72. show_h = img_h
  73. win_h = show_h + scroll_w
  74. scroll_har, scroll_var = win_w * show_w / img_w, 0
  75. f1, f2 = (img_w - show_w) / (win_w - scroll_har), 0
  76. elif img_w <= win_w and img_h > win_h:
  77. show_w = img_w
  78. win_w = show_w + scroll_w
  79. scroll_har, scroll_var = 0, win_h * show_h / img_h
  80. f1, f2 = 0, (img_h - show_h) / (win_h - scroll_var)
  81. dx, dy = dx * zoom, dy * zoom # 缩放后显示图片相对缩放图片的坐标
  82. sx, sy = dx / img_w * (win_w - scroll_har), dy / img_h * (win_h - scroll_var)
  83. img = img_zoom.copy() # 令缩放图片为原图
  84. dx, dy = int(dx), int(dy)
  85. img1 = img[dy:dy + show_h, dx:dx + show_w]
  86. dst = img1.copy()
  87. if horizontal and vertical:
  88. sx, sy = int(sx), int(sy)
  89. # 对dst1画图而非dst,避免鼠标事件不断刷新使显示图片不断进行填充
  90. dst1 = cv2.copyMakeBorder(dst, 0, scroll_w, 0, scroll_w, cv2.BORDER_CONSTANT, value=[255, 255, 255])
  91. cv2.rectangle(dst1, (sx, show_h), (int(sx + scroll_har), win_h), (181, 181, 181), -1) # 画水平滚动条
  92. cv2.rectangle(dst1, (show_w, sy), (win_w, int(sy + scroll_var)), (181, 181, 181), -1) # 画垂直滚动条
  93. elif horizontal == 0 and vertical:
  94. sx, sy = int(sx), int(sy)
  95. dst1 = cv2.copyMakeBorder(dst, 0, 0, 0, scroll_w, cv2.BORDER_CONSTANT, value=[255, 255, 255])
  96. cv2.rectangle(dst1, (show_w, sy), (win_w, int(sy + scroll_var)), (181, 181, 181), -1) # 画垂直滚动条
  97. elif horizontal and vertical == 0:
  98. sx, sy = int(sx), int(sy)
  99. dst1 = cv2.copyMakeBorder(dst, 0, scroll_w, 0, 0, cv2.BORDER_CONSTANT, value=[255, 255, 255])
  100. cv2.rectangle(dst1, (sx, show_h), (int(sx + scroll_har), win_h), (181, 181, 181), -1) # 画水平滚动条
  101. cv2.imshow("img", dst1)
  102. cv2.waitKey(1)
  103. img_original = cv2.imread("E:\\vs\\image\\2.png") # 此处需换成大于img_w * img_h的图片
  104. img_original_h, img_original_w = img_original.shape[0:2] # 原图宽高
  105. cv2.namedWindow('img', cv2.WINDOW_NORMAL)
  106. cv2.moveWindow("img", 300, 100)
  107. img = img_original.copy()
  108. img_h, img_w = img.shape[0:2] # 原图宽高
  109. show_h, show_w = 600, 800 # 显示图片宽高
  110. horizontal, vertical = 0, 0 # 原图是否超出显示图片
  111. dx, dy = 0, 0 # 显示图片相对于原图的坐标
  112. scroll_w = 16 # 滚动条宽度
  113. sx, sy = 0, 0 # 滚动块相对于滚动条的坐标
  114. flag, flag_hor, flag_ver = 0, 0, 0 # 鼠标操作类型,鼠标是否在水平滚动条上,鼠标是否在垂直滚动条上
  115. x1, y1, x2, y2, x3, y3 = 0, 0, 0, 0, 0, 0 # 中间变量
  116. win_w, win_h = show_w + scroll_w, show_h + scroll_w # 窗口宽高
  117. scroll_har, scroll_var = win_w * show_w / img_w, win_h * show_h / img_h # 滚动条水平垂直长度
  118. wheel_step, zoom = 0.05, 1 # 缩放系数, 缩放值
  119. zoom_w, zoom_h = img_w, img_h # 缩放图宽高
  120. f1, f2 = (img_w - show_w) / (win_w - scroll_har), (img_h - show_h) / (win_h - scroll_var) # 原图可移动部分占滚动条可移动部分的比例
  121. if img_h <= show_h and img_w <= show_w:
  122. cv2.imshow("img", img)
  123. else:
  124. if img_w > show_w:
  125. horizontal = 1
  126. if img_h > show_h:
  127. vertical = 1
  128. i = img[dy:dy + show_h, dx:dx + show_w]
  129. dst = i.copy()
  130. cv2.resizeWindow("img", win_w, win_h)
  131. cv2.setMouseCallback('img', mouse)
  132. cv2.waitKey()
  133. cv2.destroyAllWindows()

六、运行结果

1、水平移动图片(鼠标左键点击水平滚动条区域,一直按住右移):
在这里插入图片描述
2、垂直移动图片(鼠标左键点击垂直滚动条区域,按住并下移):
在这里插入图片描述
3、鼠标滚轮后转缩小图片
在这里插入图片描述
4、鼠标滚轮前转放大图片
在这里插入图片描述

七、不足

  水平移动或垂直移动图片后,在放大图片会出现问题。

八、参考

  1. OpenCV-Python 中文教程(段力辉 译)
  2. OpenCV图像窗口滚动条实现

发表评论

表情:
评论列表 (有 0 条评论,1503人围观)

还没有评论,来说两句吧...

相关阅读