mirror of
https://github.com/jlengrand/Tippy.git
synced 2026-03-10 08:51:16 +00:00
Adds mouse_point function to library
Implements mouse_pos function Implements corresponding tests Two modes included, single and multiple. TODO: How to tests functions needing user inputs? Signed-off-by: Julien Lengrand-Lambert <julien@lengrandlambert.fr>
This commit is contained in:
@@ -11,6 +11,77 @@ Created on Nov 19, 2011
|
|||||||
import sys
|
import sys
|
||||||
import cv
|
import cv
|
||||||
|
|
||||||
|
_mouse_pos = []
|
||||||
|
|
||||||
|
def _on_mouse(event, x, y, flags, param):
|
||||||
|
"""
|
||||||
|
None = onMouse(event, x, y, flags, param)
|
||||||
|
|
||||||
|
Function automatically called by opencv when having mouse events on a
|
||||||
|
displayed frame. In here, we are searching for a left mouse click
|
||||||
|
"""
|
||||||
|
global _mouse_pos
|
||||||
|
if event == cv.CV_EVENT_LBUTTONDOWN :
|
||||||
|
_mouse_pos.append((x, y))
|
||||||
|
|
||||||
|
def mouse_point(img, name="Mouse Points", mode="S"):
|
||||||
|
"""
|
||||||
|
Displays input image and waits for user click on a point of the image.
|
||||||
|
For each click, the (x, y) coordinates are retrieved.
|
||||||
|
|
||||||
|
Two modes are possible:
|
||||||
|
-Single :
|
||||||
|
The function exits automatically on first click.
|
||||||
|
Returns a list containing 1 (x,y) tuple.
|
||||||
|
-Multiple :
|
||||||
|
All clicks are saved. The function exists when the user types on keyboard
|
||||||
|
Returns containing (x,y) tuples.
|
||||||
|
---
|
||||||
|
Ex:
|
||||||
|
img = cv.LoadImage("../data/tippy.jpg", cv.CV_LOAD_IMAGE_GRAYSCALE)
|
||||||
|
mouse_points(img, name="mouse points", mode="S")
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not isinstance(name, str):
|
||||||
|
raise TypeError("(%s) Name :String expected!" % (sys._getframe().f_code.co_name))
|
||||||
|
if not isinstance(mode, str):
|
||||||
|
raise TypeError("(%s) Mode :String expected!" % (sys._getframe().f_code.co_name))
|
||||||
|
|
||||||
|
global _mouse_pos
|
||||||
|
cv.StartWindowThread()
|
||||||
|
cv.NamedWindow(name, cv.CV_WINDOW_AUTOSIZE)
|
||||||
|
cv.SetMouseCallback(name, _on_mouse)
|
||||||
|
|
||||||
|
try :
|
||||||
|
cv.ShowImage(name, img)
|
||||||
|
except TypeError:
|
||||||
|
raise TypeError("(%s) img : IplImage expected!" % (sys._getframe().f_code.co_name))
|
||||||
|
|
||||||
|
if mode == "S":
|
||||||
|
_single_point()
|
||||||
|
elif mode == "M":
|
||||||
|
_multiple_points()
|
||||||
|
else:
|
||||||
|
raise ValueError("(%s) Mode can be either S (single) or M (multiple)" % (sys._getframe().f_code.co_name))
|
||||||
|
|
||||||
|
cv.DestroyWindow(name)
|
||||||
|
return _mouse_pos
|
||||||
|
|
||||||
|
def _single_point():
|
||||||
|
"""
|
||||||
|
Internal function, used in mouse_point
|
||||||
|
"""
|
||||||
|
while(len(_mouse_pos) == 0):
|
||||||
|
cv.WaitKey(10)
|
||||||
|
|
||||||
|
def _multiple_points():
|
||||||
|
"""
|
||||||
|
Internal function, used in mouse_point
|
||||||
|
"""
|
||||||
|
char = -1
|
||||||
|
while (char == -1):
|
||||||
|
char = cv.WaitKey(10)
|
||||||
|
# ----
|
||||||
def create_same_image(in_img, zero=0):
|
def create_same_image(in_img, zero=0):
|
||||||
"""
|
"""
|
||||||
Creates an image of same size, depth and number of channels as input image
|
Creates an image of same size, depth and number of channels as input image
|
||||||
@@ -31,4 +102,6 @@ def create_same_image(in_img, zero=0):
|
|||||||
if zero:
|
if zero:
|
||||||
cv.Zero(out_img)
|
cv.Zero(out_img)
|
||||||
|
|
||||||
return out_img
|
return out_img
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,11 @@ def simple_region_growing(img, seed, threshold=1):
|
|||||||
Outputs a single channel 8 bits binary (0 or 255) image. Extracted region is highlighted in white.
|
Outputs a single channel 8 bits binary (0 or 255) image. Extracted region is highlighted in white.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
dims = cv.GetSize(img)
|
||||||
|
except TypeError:
|
||||||
|
raise TypeError("(%s) img : IplImage expected!" % (sys._getframe().f_code.co_name))
|
||||||
|
|
||||||
# img test
|
# img test
|
||||||
if not(img.depth == cv.IPL_DEPTH_8U):
|
if not(img.depth == cv.IPL_DEPTH_8U):
|
||||||
raise TypeError("(%s) 8U image expected!" % (sys._getframe().f_code.co_name))
|
raise TypeError("(%s) 8U image expected!" % (sys._getframe().f_code.co_name))
|
||||||
@@ -34,7 +39,7 @@ def simple_region_growing(img, seed, threshold=1):
|
|||||||
if not((isinstance(seed, tuple)) and (len(seed) is 2) ) :
|
if not((isinstance(seed, tuple)) and (len(seed) is 2) ) :
|
||||||
raise TypeError("(%s) (x, y) variable expected!" % (sys._getframe().f_code.co_name))
|
raise TypeError("(%s) (x, y) variable expected!" % (sys._getframe().f_code.co_name))
|
||||||
|
|
||||||
dims = cv.GetSize(img)
|
|
||||||
if (seed[0] or seed[1] ) < 0 :
|
if (seed[0] or seed[1] ) < 0 :
|
||||||
raise ValueError("(%s) Seed should have positive values!" % (sys._getframe().f_code.co_name))
|
raise ValueError("(%s) Seed should have positive values!" % (sys._getframe().f_code.co_name))
|
||||||
elif ((seed[0] > dims[0]) or (seed[1] > dims[1])):
|
elif ((seed[0] > dims[0]) or (seed[1] > dims[1])):
|
||||||
|
|||||||
@@ -24,6 +24,11 @@ class Test(unittest.TestCase):
|
|||||||
self.img_3c = cv.LoadImage("../data/tippy.jpg", cv.CV_LOAD_IMAGE_COLOR) # 3 channel image
|
self.img_3c = cv.LoadImage("../data/tippy.jpg", cv.CV_LOAD_IMAGE_COLOR) # 3 channel image
|
||||||
self.img_fake_2c = cv.CreateImage((15, 15), cv.IPL_DEPTH_8U, 2) # 2 channels
|
self.img_fake_2c = cv.CreateImage((15, 15), cv.IPL_DEPTH_8U, 2) # 2 channels
|
||||||
self.fake_img = 10 # non Image
|
self.fake_img = 10 # non Image
|
||||||
|
|
||||||
|
self.false_mode = "A" # non True/False (or 0/1) argument
|
||||||
|
self.fake_mode = 100 # non True/False (or 0/1) argument
|
||||||
|
self.fake_name = 100 # non True/False (or 0/1) argument
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
"""
|
"""
|
||||||
This method is called after each test
|
This method is called after each test
|
||||||
@@ -40,5 +45,15 @@ class Test(unittest.TestCase):
|
|||||||
self.assertEqual(cv.GetSize(img), cv.GetSize(out_img))
|
self.assertEqual(cv.GetSize(img), cv.GetSize(out_img))
|
||||||
self.assertRaises(TypeError, lambda: bo.create_same_image(self.fake_img))
|
self.assertRaises(TypeError, lambda: bo.create_same_image(self.fake_img))
|
||||||
|
|
||||||
|
def test_mouse_point(self):
|
||||||
|
# img test
|
||||||
|
self.assertRaises(TypeError, lambda: bo.mouse_point(self.fake_img))
|
||||||
|
# name test
|
||||||
|
self.assertRaises(TypeError, lambda: bo.mouse_point(self.fake_name))
|
||||||
|
# mode test
|
||||||
|
self.assertRaises(TypeError, lambda: bo.mouse_point(self.fake_mode))
|
||||||
|
self.assertRaises(ValueError, lambda: bo.mouse_point(self.false_mode))
|
||||||
|
# TODO: How to test arguments that need user interaction?
|
||||||
|
|
||||||
#if __name__ == "__main__":
|
#if __name__ == "__main__":
|
||||||
#unittest.main()
|
#unittest.main()
|
||||||
@@ -44,6 +44,8 @@ class Test(unittest.TestCase):
|
|||||||
# Image type tests
|
# Image type tests
|
||||||
self.assertRaises(TypeError, lambda: se.simple_region_growing(self.img_3c, self.seed))
|
self.assertRaises(TypeError, lambda: se.simple_region_growing(self.img_3c, self.seed))
|
||||||
self.assertRaises(TypeError, lambda: se.simple_region_growing(self.img_16s, self.seed))
|
self.assertRaises(TypeError, lambda: se.simple_region_growing(self.img_16s, self.seed))
|
||||||
|
self.assertRaises(TypeError, lambda: se.simple_region_growing(self.fake_img, self.seed))
|
||||||
|
|
||||||
# Threshold tests
|
# Threshold tests
|
||||||
self.assertRaises(ValueError, lambda: se.simple_region_growing(self.img_1c, self.seed, self.neg_thres))
|
self.assertRaises(ValueError, lambda: se.simple_region_growing(self.img_1c, self.seed, self.neg_thres))
|
||||||
self.assertRaises(TypeError, lambda: se.simple_region_growing(self.img_1c, self.seed, self.bad_thres))
|
self.assertRaises(TypeError, lambda: se.simple_region_growing(self.img_1c, self.seed, self.bad_thres))
|
||||||
|
|||||||
Reference in New Issue
Block a user