Python 创建轨迹栏以滚动大图像和上下边界(Pyhton/OpenCV)
我试图在OpenCv python创建的窗口中创建滚动条。具体来说,我想将答案(1)中的HSV滚动条形码与答案(2)中的放大缩小滚动条形码合并。两者都是分开工作的,但我想在同一个窗口中使用它们 代码(1)( 代码(2)Python 创建轨迹栏以滚动大图像和上下边界(Pyhton/OpenCV),python,opencv,trackbar,Python,Opencv,Trackbar,我试图在OpenCv python创建的窗口中创建滚动条。具体来说,我想将答案(1)中的HSV滚动条形码与答案(2)中的放大缩小滚动条形码合并。两者都是分开工作的,但我想在同一个窗口中使用它们 代码(1)( 代码(2) #-*-编码:utf-8-*- 进口cv2 将numpy作为np导入 类PanZoomWindow(对象): “”“控制OpenCV窗口。注册鼠标侦听器以便: 1.右上/右下拖动可放大/缩小 2.右键单击重新居中 3.轨迹栏可垂直和水平滚动 如果指定不同的窗口名称,可以一次打开多
#-*-编码:utf-8-*-
进口cv2
将numpy作为np导入
类PanZoomWindow(对象):
“”“控制OpenCV窗口。注册鼠标侦听器以便:
1.右上/右下拖动可放大/缩小
2.右键单击重新居中
3.轨迹栏可垂直和水平滚动
如果指定不同的窗口名称,可以一次打开多个窗口。
您可以传入一个onLeftClickFunction,当用户左键单击时,这个
将调用onLeftClickFunction(y,x),y,x在原始图像坐标中。”“”
def u uu init_uuuuu(self、img、windowName='PanZoomWindow',onLeftClickFunction=None):
self.WINDOW\u NAME=windowName
self.H\u轨迹栏\u名称='x'
self.V\u轨迹栏\u名称='y'
self.img=img
self.onLeftClickFunction=onLeftClickFunction
self.TRACKBAR_TICKS=1000
self.panAndZoomState=panAndZoomState(img.shape,self)
self.lButtonDownLoc=无
self.mbuttonownloc=无
self.rButtonDownLoc=无
cv2.namedWindow(self.WINDOW\u NAME,cv2.WINDOW\u NORMAL)
self.redrawImage()
cv2.setMouseCallback(self.WINDOW\u NAME,self.onMouse)
cv2.createTrackbar(self.H\u TRACKBAR\u NAME、self.WINDOW\u NAME、0、self.TRACKBAR\u TICKS、self.onHTrackbarMove)
cv2.createTrackbar(self.V\u TRACKBAR\u NAME、self.WINDOW\u NAME、0、self.TRACKBAR\u TICKS、self.onVTrackbarMove)
定义鼠标(自身、事件、x、y、_ignore1、_ignore2):
“”“响应窗口中的鼠标事件。
x和y是当前显示图像中的像素坐标。
如果用户已放大,则显示的图像是一个子区域,因此您需要
添加self.panAndZoomState.ul以获取完整图像中的坐标。”“”
如果event==cv2.event\u MOUSEMOVE:
返回
elif event==cv2.event\u RBUTTONDOWN:
#记录用户开始右拖动的位置
self.mbuttonownloc=np.array([y,x])
elif event==cv2.event\RBUTTONUP和self.MBUTDOWNLOC不是无:
#用户刚刚完成正确的拖动
dy=y-自.mButtonDownLoc[0]
pixelsPerDoubling=0.2*self.panAndZoomState.shape[0]#lower=zoom more
变化因子=(1.0+绝对值(dy)/像素倍增)
变更系数=最小值(最大值(1.0,变更系数),5.0)
如果变化系数<1.05:
dy=0#这是一次点击,不是画图。所以不要缩放,只需重新居中即可。
如果dy>0:#向下移动,则缩小。
zoomInFactor=1.0/changeFactor
其他:
zoomInFactor=changeFactor
#打印(“缩放因子:%s”%zoomFactor)
self.panAndZoomState.zoom(self.mButtonDownLoc[0],self.mButtonDownLoc[1],zoomInFactor)
elif event==cv2.event\u LBUTTONDOWN:
#用户按下了左键。
coordsInDisplayedImage=np.array([y,x])
如果np.any(CoordsInDisplayeImage<0)或np.any(CoordsInDisplayeImage>self.panAndZoomState.shape[:2]):
打印(“您在图像区域外单击了”)
其他:
打印(“您在缩放的矩形“%CoordsInDisplayeImage”中单击了%s)
coordsInFullImage=self.panAndZoomState.ul+CoordsInDisplayeImage
打印(“这是实际图像“%CoordsFullImage”中的%s)
打印(“此像素包含%s,%s%”(self.img[coordsInFullImage[0],coordsInFullImage[1]]))
如果self.onLeftClickFunction不是None:
self.onLeftClickFunction(coordsInFullImage[0],coordsInFullImage[1])
#您可以在此处处理其他鼠标单击事件
def ON VTRACKBARMOVE(自身,勾选位置):
self.panAndZoomState.setYFractionOffset(浮动(滴答声位置)/self.TRACKBAR_滴答声)
def onHTrackbarMove(自身,勾选位置):
self.panAndZoomState.setXFractionOffset(float(tickPosition)/self.TRACKBAR_TICKS)
def重绘图像(自):
pzs=self.panAndZoomState
cv2.imshow(self.WINDOW_NAME,self.img[pzs.ul[0]:pzs.ul[0]+pzs.shape[0]、pzs.ul[1]:pzs.ul[1]+pzs.shape[1])
类PanAndZoomState(对象):
“”“跟踪当前显示的图像矩形。
进行数学运算以将此矩形调整为平移和缩放。”“”
最小形状=np.数组([50,50])
定义初始化(self、imShape、parentWindow):
self.ul=np.array([0,0])#缩放矩形的左上角(表示为y,x)
self.imShape=np.array(imShape[0:2])
self.shape=self.imShape#矩形的当前尺寸
self.parentWindow=父窗口
def缩放(自缩放、相对缩放、相对缩放、缩放因子):
self.shape=(self.shape.astype(np.float)/zoomInFactor.astype(np.int)
#如果可能,将视图扩展为方形。(我不知道如何获得实际的窗口纵横比)
self.shape[:]=np.max(self.shape)
self.shape=np.max(PanAndZoomState.MIN_shape,self.shape)#防止放大过远
c=self.ul+np.array([relativeCy,relativeCx])
self.ul=(c-self.shape/2).astype(np.int)
self.\u fixBoundsAndDraw()
定义固定边界和绘制(自):
“”“确保我们没有在图像外滚动/缩放。
然后绘制当前显示的图像矩形。”“”
#打印(“在self.ul中:%s形状:%s”%(self.ul,self.shape))
self.ul=np.最大值(0,np.最小值(self.ul,self.imShape-self.shape))
self.shape=np.minimum(np.maximum(PanAndZoomState.minu-shape,self.shape),self.imShape-self.ul)
#打印(“输出self.ul:%s形状:%s”%(self.ul,s
def nothing(x):
pass
# Load image
image = cv2.imread("XXX.jpg")
# Create a window
cv2.namedWindow('image')
# Resize a window
cv2.resizeWindow('image', 1,1)
# Create trackbars for color change
# Hue is from 0-179 for Opencv
cv2.createTrackbar('HMin', 'image', 0, 179, nothing)
cv2.createTrackbar('SMin', 'image', 0, 255, nothing)
cv2.createTrackbar('VMin', 'image', 0, 255, nothing)
cv2.createTrackbar('HMax', 'image', 0, 179, nothing)
cv2.createTrackbar('SMax', 'image', 0, 255, nothing)
cv2.createTrackbar('VMax', 'image', 0, 255, nothing)
# Set default value for Max HSV trackbars
cv2.setTrackbarPos('HMax', 'image', 179)
cv2.setTrackbarPos('SMax', 'image', 255)
cv2.setTrackbarPos('VMax', 'image', 255)
# Initialize HSV min/max values
hMin = sMin = vMin = hMax = sMax = vMax = 0
phMin = psMin = pvMin = phMax = psMax = pvMax = 0
while(1):
# Get current positions of all trackbars
hMin = cv2.getTrackbarPos('HMin', 'image')
sMin = cv2.getTrackbarPos('SMin', 'image')
vMin = cv2.getTrackbarPos('VMin', 'image')
hMax = cv2.getTrackbarPos('HMax', 'image')
sMax = cv2.getTrackbarPos('SMax', 'image')
vMax = cv2.getTrackbarPos('VMax', 'image')
# Set minimum and maximum HSV values to display
lower = np.array([hMin, sMin, vMin])
upper = np.array([hMax, sMax, vMax])
# Convert to HSV format and color threshold
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, lower, upper)
result = cv2.bitwise_and(image, image, mask=mask)
# Print if there is a change in HSV value
if((phMin != hMin) | (psMin != sMin) | (pvMin != vMin) | (phMax != hMax) | (psMax != sMax) | (pvMax != vMax) ):
print("(hMin = %d , sMin = %d, vMin = %d), (hMax = %d , sMax = %d, vMax = %d)" % (hMin , sMin , vMin, hMax, sMax , vMax))
phMin = hMin
psMin = sMin
pvMin = vMin
phMax = hMax
psMax = sMax
pvMax = vMax
# Display result image
cv2.imshow('image', result)
if cv2.waitKey(10) & 0xFF == ord('q'):
break
# -*- coding: utf-8 -*-
import cv2
import numpy as np
class PanZoomWindow(object):
""" Controls an OpenCV window. Registers a mouse listener so that:
1. right-dragging up/down zooms in/out
2. right-clicking re-centers
3. trackbars scroll vertically and horizontally
You can open multiple windows at once if you specify different window names.
You can pass in an onLeftClickFunction, and when the user left-clicks, this
will call onLeftClickFunction(y,x), with y,x in original image coordinates."""
def __init__(self, img, windowName = 'PanZoomWindow', onLeftClickFunction = None):
self.WINDOW_NAME = windowName
self.H_TRACKBAR_NAME = 'x'
self.V_TRACKBAR_NAME = 'y'
self.img = img
self.onLeftClickFunction = onLeftClickFunction
self.TRACKBAR_TICKS = 1000
self.panAndZoomState = PanAndZoomState(img.shape, self)
self.lButtonDownLoc = None
self.mButtonDownLoc = None
self.rButtonDownLoc = None
cv2.namedWindow(self.WINDOW_NAME, cv2.WINDOW_NORMAL)
self.redrawImage()
cv2.setMouseCallback(self.WINDOW_NAME, self.onMouse)
cv2.createTrackbar(self.H_TRACKBAR_NAME, self.WINDOW_NAME, 0, self.TRACKBAR_TICKS, self.onHTrackbarMove)
cv2.createTrackbar(self.V_TRACKBAR_NAME, self.WINDOW_NAME, 0, self.TRACKBAR_TICKS, self.onVTrackbarMove)
def onMouse(self,event, x,y,_ignore1,_ignore2):
""" Responds to mouse events within the window.
The x and y are pixel coordinates in the image currently being displayed.
If the user has zoomed in, the image being displayed is a sub-region, so you'll need to
add self.panAndZoomState.ul to get the coordinates in the full image."""
if event == cv2.EVENT_MOUSEMOVE:
return
elif event == cv2.EVENT_RBUTTONDOWN:
#record where the user started to right-drag
self.mButtonDownLoc = np.array([y,x])
elif event == cv2.EVENT_RBUTTONUP and self.mButtonDownLoc is not None:
#the user just finished right-dragging
dy = y - self.mButtonDownLoc[0]
pixelsPerDoubling = 0.2*self.panAndZoomState.shape[0] #lower = zoom more
changeFactor = (1.0+abs(dy)/pixelsPerDoubling)
changeFactor = min(max(1.0,changeFactor),5.0)
if changeFactor < 1.05:
dy = 0 #this was a click, not a draw. So don't zoom, just re-center.
if dy > 0: #moved down, so zoom out.
zoomInFactor = 1.0/changeFactor
else:
zoomInFactor = changeFactor
# print("zoomFactor: %s"%zoomFactor)
self.panAndZoomState.zoom(self.mButtonDownLoc[0], self.mButtonDownLoc[1], zoomInFactor)
elif event == cv2.EVENT_LBUTTONDOWN:
#the user pressed the left button.
coordsInDisplayedImage = np.array([y,x])
if np.any(coordsInDisplayedImage < 0) or np.any(coordsInDisplayedImage > self.panAndZoomState.shape[:2]):
print("you clicked outside the image area")
else:
print("you clicked on %s within the zoomed rectangle"%coordsInDisplayedImage)
coordsInFullImage = self.panAndZoomState.ul + coordsInDisplayedImage
print("this is %s in the actual image"%coordsInFullImage)
print("this pixel holds %s, %s"%(self.img[coordsInFullImage[0],coordsInFullImage[1]]))
if self.onLeftClickFunction is not None:
self.onLeftClickFunction(coordsInFullImage[0],coordsInFullImage[1])
#you can handle other mouse click events here
def onVTrackbarMove(self,tickPosition):
self.panAndZoomState.setYFractionOffset(float(tickPosition)/self.TRACKBAR_TICKS)
def onHTrackbarMove(self,tickPosition):
self.panAndZoomState.setXFractionOffset(float(tickPosition)/self.TRACKBAR_TICKS)
def redrawImage(self):
pzs = self.panAndZoomState
cv2.imshow(self.WINDOW_NAME, self.img[pzs.ul[0]:pzs.ul[0]+pzs.shape[0], pzs.ul[1]:pzs.ul[1]+pzs.shape[1]])
class PanAndZoomState(object):
""" Tracks the currently-shown rectangle of the image.
Does the math to adjust this rectangle to pan and zoom."""
MIN_SHAPE = np.array([50,50])
def __init__(self, imShape, parentWindow):
self.ul = np.array([0,0]) #upper left of the zoomed rectangle (expressed as y,x)
self.imShape = np.array(imShape[0:2])
self.shape = self.imShape #current dimensions of rectangle
self.parentWindow = parentWindow
def zoom(self,relativeCy,relativeCx,zoomInFactor):
self.shape = (self.shape.astype(np.float)/zoomInFactor).astype(np.int)
#expands the view to a square shape if possible. (I don't know how to get the actual window aspect ratio)
self.shape[:] = np.max(self.shape)
self.shape = np.maximum(PanAndZoomState.MIN_SHAPE,self.shape) #prevent zooming in too far
c = self.ul+np.array([relativeCy,relativeCx])
self.ul = (c-self.shape/2).astype(np.int)
self._fixBoundsAndDraw()
def _fixBoundsAndDraw(self):
""" Ensures we didn't scroll/zoom outside the image.
Then draws the currently-shown rectangle of the image."""
# print("in self.ul: %s shape: %s"%(self.ul,self.shape))
self.ul = np.maximum(0,np.minimum(self.ul, self.imShape-self.shape))
self.shape = np.minimum(np.maximum(PanAndZoomState.MIN_SHAPE,self.shape), self.imShape-self.ul)
# print("out self.ul: %s shape: %s"%(self.ul,self.shape))
yFraction = float(self.ul[0])/max(1,self.imShape[0]-self.shape[0])
xFraction = float(self.ul[1])/max(1,self.imShape[1]-self.shape[1])
cv2.setTrackbarPos(self.parentWindow.H_TRACKBAR_NAME, self.parentWindow.WINDOW_NAME,int(xFraction*self.parentWindow.TRACKBAR_TICKS))
cv2.setTrackbarPos(self.parentWindow.V_TRACKBAR_NAME, self.parentWindow.WINDOW_NAME,int(yFraction*self.parentWindow.TRACKBAR_TICKS))
self.parentWindow.redrawImage()
def setYAbsoluteOffset(self,yPixel):
self.ul[0] = min(max(0,yPixel), self.imShape[0]-self.shape[0])
self._fixBoundsAndDraw()
def setXAbsoluteOffset(self,xPixel):
self.ul[1] = min(max(0,xPixel), self.imShape[1]-self.shape[1])
self._fixBoundsAndDraw()
def setYFractionOffset(self,fraction):
""" pans so the upper-left zoomed rectange is "fraction" of the way down the image."""
self.ul[0] = int(round((self.imShape[0]-self.shape[0])*fraction))
self._fixBoundsAndDraw()
def setXFractionOffset(self,fraction):
""" pans so the upper-left zoomed rectange is "fraction" of the way right on the image."""
self.ul[1] = int(round((self.imShape[1]-self.shape[1])*fraction))
self._fixBoundsAndDraw()
if __name__ == "__main__":
infile = "XXX.jpg"
myImage = cv2.imread(infile,cv2.IMREAD_ANYCOLOR)
window = PanZoomWindow(myImage, "test window")
key = -1
while key != ord('q') and key != 27: # 27 = escape key
#the OpenCV window won't display until you call cv2.waitKey()
key = cv2.waitKey(5) #User can press 'q' or ESC to exit.
cv2.destroyAllWindows()