OpenCV-检测不包括阴影的对象
OpenCV- Detecting objects excluding shadows
我正在开发一种从鸟瞰图检测汽车的方法。我正在使用 scikit 包来计算空停车场图像和有车的停车场的差异以检测异物。然后我画了汽车周围的最小面积矩形。
没有阴影时效果很好。
空停车场图片(请忽略栗色车)
没有阴影
有阴影(问题)
有车影的时候,也在最小面积矩形内。如何从矩形中排除阴影?
这是我的来源
import numpy as np
from skimage.measure import compare_ssim
import imutils
from cv2 import cv2
# construct the argument parse and parse the arguments
# load the two input images
imageA = cv2.imread('empty-lot.png')
imageB = cv2.imread('two-car-lot-shadow.png')
# convert the images to grayscale
grayA = cv2.cvtColor(imageA, cv2.COLOR_BGR2GRAY)
grayB = cv2.cvtColor(imageB, cv2.COLOR_BGR2GRAY)
# compute the Structural Similarity Index (SSIM) between the two
# images, ensuring that the difference image is returned
(score, diff) = compare_ssim(grayA, grayB, full=True, gaussian_weights=True, sigma=4)
diff = (diff * 255).astype("uint8")
print("SSIM: {}".format(score))
# threshold the difference image, followed by finding contours to
# obtain the regions of the two input images that differ
thresh = cv2.threshold(diff, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]
# loop over the contours
for c in cnts:
# compute the min area rect of the contour and area
rect = cv2.minAreaRect(c)
box = cv2.boxPoints(rect)
area = cv2.contourArea(c)
# remove small contour areas
if area < 10000: continue
# convert all coordinates floating point values to int
box = np.int0(box)
# draw a green rectangle
cv2.drawContours(imageB, [box], 0, (0, 255, 0), 2)
# show the output images
cv2.imshow("Modified", imageB)
cv2.imshow("Thresh", thresh)
k = cv2.waitKey() & 0xFF
if k == 27:
exit()
您可以将图片格式转换为HSV格式,去除阴影很容易。
import ctypes
import numpy as np
import cv2
from pathlib import Path
from typing import List, Union, Callable
def main():
img_bgr: np.ndarray = cv2.imread(str(Path('parking.jpg')))
img_hsv: np.ndarray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(src=img_hsv, lowerb=np.array([0, 64, 153]), upperb=np.array([179, 255, 255]))
img_hsv_modify: np.ndarray = cv2.bitwise_and(img_bgr, img_bgr, mask=mask)
# show_img(img_hsv_modify)
img_mask_gray = cv2.cvtColor(img_hsv_modify, cv2.COLOR_BGR2GRAY)
threshold_val, img_bit = cv2.threshold(img_mask_gray, 0, 255, cv2.THRESH_BINARY) # type: float, np.ndarray
contours, hierarchy = cv2.findContours(img_bit, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
img_bgr_copy = np.copy(img_bgr)
for cnt in filter(lambda c: cv2.contourArea(c) > 10000, contours):
box = cv2.boxPoints(cv2.minAreaRect(cnt))
cv2.drawContours(img_bgr_copy, [np.int0(box)], -1, color=(0, 255, 0), thickness=2)
show_img([img_bgr, img_hsv_modify, cv2.cvtColor(img_bit, cv2.COLOR_GRAY2BGR), img_bgr_copy],
note=['original', 'hsv modify', 'bit', 'result'])
show_img(img_bgr_copy)
if __name__ == '__main__':
main()
你可能会问我怎么知道下限和上限。 (请看扩展码:control_bar_hsv.py)
mask = cv2.inRange(src=img_hsv, lowerb=np.array([0, 64, 153]), upperb=np.array([179, 255, 255]))
结果:
所有图片:
分机号
show_img:
def show_img(img_list: Union[np.ndarray, List[np.ndarray]], combine_fun: Callable = np.vstack,
window_name='demo', window_size=(ctypes.windll.user32.GetSystemMetrics(0) // 2, ctypes.windll.user32.GetSystemMetrics(1) // 2),
delay_time=0, note: Union[str, List[str]] = None, **options):
if isinstance(img_list, np.ndarray):
img_list = [img_list]
if isinstance(note, str):
print(note)
cv2.namedWindow(window_name, cv2.WINDOW_NORMAL)
if window_size:
w, h = window_size
cv2.resizeWindow(window_name, w, h)
result_list = []
for idx, img in enumerate(img_list):
img = np.copy(img)
if note and isinstance(note, list) and idx < len(note):
cv2.putText(img, note[idx], org=options.get('org', (50, 50)),
fontFace=options.get('fontFace', cv2.FONT_HERSHEY_SIMPLEX),
fontScale=options.get('fontScale', 2), color=(0, 255, 255), thickness=4)
result_list.append(img)
cv2.imshow(window_name, combine_fun(result_list))
cv2.waitKey(delay_time)
control_bar_hsv.py
使用起来很简单,只需复制粘贴然后告诉它你的图片路径在哪里,就完成了。
如果你想创建其他control_bar,也许ControlBarBase
会帮助你写更少的代码。
"""
control_bar_hsv.py
"""
import cv2
from pathlib import Path
import numpy as np
import ctypes
import functools
from typing import Tuple, Callable
class ControlBarBase:
__slots__ = ('img_bgr',)
WAIT_TIME = 500 # milliseconds
CONTROL_PANEL_NAME = 'control_panel'
IMAGE_PANEL_NAME = 'image'
SCREEN_SIZE: Tuple[int, int] = None
def __init__(self, img_path: Path):
self.img_bgr: np.ndarray = cv2.imread(str(img_path))
self.init_window()
self.init_track_bar()
def init_window(self):
for name in (self.CONTROL_PANEL_NAME, self.IMAGE_PANEL_NAME):
cv2.namedWindow(name, cv2.WINDOW_NORMAL)
if self.SCREEN_SIZE:
screen_width, screen_height = self.SCREEN_SIZE
cv2.resizeWindow(name, int(screen_width), int(screen_height))
def init_track_bar(self):
"""
self.build_track_bar(label_name, range_lim=(0, 255), default_value=0, callback)
"""
raise NotImplementedError('subclasses of _ControlBarBase must provide a init_track_bar() method')
def render(self):
raise NotImplementedError('subclasses of _ControlBarBase must provide a render() method.')
def build_track_bar(self, label_name: str,
range_lim: Tuple[int, int], default_value: int, callback: Callable = lambda x: ...):
min_val, max_val = range_lim
cv2.createTrackbar(label_name, self.CONTROL_PANEL_NAME, min_val, max_val, callback)
cv2.setTrackbarPos(label_name, self.CONTROL_PANEL_NAME, default_value)
def get_trackbar_pos(self, widget_name: str):
return cv2.getTrackbarPos(widget_name, self.CONTROL_PANEL_NAME)
def run(self):
while 1:
img, callback_func = self.render()
cv2.imshow(self.IMAGE_PANEL_NAME, img)
if (cv2.waitKey(self.WAIT_TIME) & 0xFF == ord('q') or
cv2.getWindowProperty(self.IMAGE_PANEL_NAME, 0) == -1 or
cv2.getWindowProperty(self.CONTROL_PANEL_NAME, 0) == -1):
callback_func()
break
cv2.destroyAllWindows()
class ControlBarHSV(ControlBarBase):
__slots__ = ()
WAIT_TIME = 500
SCREEN_SIZE = ctypes.windll.user32.GetSystemMetrics(0) / 2, ctypes.windll.user32.GetSystemMetrics(1) / 2
def init_track_bar(self):
self.build_track_bar('HMin', range_lim=(0, 179), default_value=0)
self.build_track_bar('SMin', (0, 255), 0)
self.build_track_bar('VMin', (0, 255), 0)
self.build_track_bar('HMax', (0, 179), 179)
self.build_track_bar('SMax', (0, 255), 255)
self.build_track_bar('VMax', (0, 255), 255)
def render(self):
# get current positions of all trackbars
h_min = self.get_trackbar_pos('HMin')
s_min = self.get_trackbar_pos('SMin')
v_min = self.get_trackbar_pos('VMin')
h_max = self.get_trackbar_pos('HMax')
s_max = self.get_trackbar_pos('SMax')
v_max = self.get_trackbar_pos('VMax')
# Set minimum and max HSV values to display
lower = np.array([h_min, s_min, v_min])
upper = np.array([h_max, s_max, v_max])
# Create HSV Image and threshold into a range.
hsv = cv2.cvtColor(self.img_bgr, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, lower, upper)
img_output: np.ndarray = cv2.bitwise_and(self.img_bgr, self.img_bgr, mask=mask)
@functools.wraps(self.render)
def cb_func():
return print(f'cv2.inRange(src=hsv, lowerb=np.array([{h_min}, {s_min}, {v_min}]), upperb=np.array([{h_max}, {s_max}, {v_max}]))')
return img_output, cb_func
if __name__ == '__main__':
from argparse import ArgumentParser
arg_parser = ArgumentParser()
arg_parser.add_argument("src_path", type=Path, help="source image path")
args = arg_parser.parse_args()
obj = ControlBarHSV(args.src_path) # ControlBarHSV(Path('parking.jpg'))
obj.run()
我正在开发一种从鸟瞰图检测汽车的方法。我正在使用 scikit 包来计算空停车场图像和有车的停车场的差异以检测异物。然后我画了汽车周围的最小面积矩形。
没有阴影时效果很好。
空停车场图片(请忽略栗色车)
没有阴影
有阴影(问题)
有车影的时候,也在最小面积矩形内。如何从矩形中排除阴影?
这是我的来源
import numpy as np
from skimage.measure import compare_ssim
import imutils
from cv2 import cv2
# construct the argument parse and parse the arguments
# load the two input images
imageA = cv2.imread('empty-lot.png')
imageB = cv2.imread('two-car-lot-shadow.png')
# convert the images to grayscale
grayA = cv2.cvtColor(imageA, cv2.COLOR_BGR2GRAY)
grayB = cv2.cvtColor(imageB, cv2.COLOR_BGR2GRAY)
# compute the Structural Similarity Index (SSIM) between the two
# images, ensuring that the difference image is returned
(score, diff) = compare_ssim(grayA, grayB, full=True, gaussian_weights=True, sigma=4)
diff = (diff * 255).astype("uint8")
print("SSIM: {}".format(score))
# threshold the difference image, followed by finding contours to
# obtain the regions of the two input images that differ
thresh = cv2.threshold(diff, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]
# loop over the contours
for c in cnts:
# compute the min area rect of the contour and area
rect = cv2.minAreaRect(c)
box = cv2.boxPoints(rect)
area = cv2.contourArea(c)
# remove small contour areas
if area < 10000: continue
# convert all coordinates floating point values to int
box = np.int0(box)
# draw a green rectangle
cv2.drawContours(imageB, [box], 0, (0, 255, 0), 2)
# show the output images
cv2.imshow("Modified", imageB)
cv2.imshow("Thresh", thresh)
k = cv2.waitKey() & 0xFF
if k == 27:
exit()
您可以将图片格式转换为HSV格式,去除阴影很容易。
import ctypes
import numpy as np
import cv2
from pathlib import Path
from typing import List, Union, Callable
def main():
img_bgr: np.ndarray = cv2.imread(str(Path('parking.jpg')))
img_hsv: np.ndarray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(src=img_hsv, lowerb=np.array([0, 64, 153]), upperb=np.array([179, 255, 255]))
img_hsv_modify: np.ndarray = cv2.bitwise_and(img_bgr, img_bgr, mask=mask)
# show_img(img_hsv_modify)
img_mask_gray = cv2.cvtColor(img_hsv_modify, cv2.COLOR_BGR2GRAY)
threshold_val, img_bit = cv2.threshold(img_mask_gray, 0, 255, cv2.THRESH_BINARY) # type: float, np.ndarray
contours, hierarchy = cv2.findContours(img_bit, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
img_bgr_copy = np.copy(img_bgr)
for cnt in filter(lambda c: cv2.contourArea(c) > 10000, contours):
box = cv2.boxPoints(cv2.minAreaRect(cnt))
cv2.drawContours(img_bgr_copy, [np.int0(box)], -1, color=(0, 255, 0), thickness=2)
show_img([img_bgr, img_hsv_modify, cv2.cvtColor(img_bit, cv2.COLOR_GRAY2BGR), img_bgr_copy],
note=['original', 'hsv modify', 'bit', 'result'])
show_img(img_bgr_copy)
if __name__ == '__main__':
main()
你可能会问我怎么知道下限和上限。 (请看扩展码:control_bar_hsv.py)
mask = cv2.inRange(src=img_hsv, lowerb=np.array([0, 64, 153]), upperb=np.array([179, 255, 255]))
结果:
所有图片:
分机号
show_img:
def show_img(img_list: Union[np.ndarray, List[np.ndarray]], combine_fun: Callable = np.vstack,
window_name='demo', window_size=(ctypes.windll.user32.GetSystemMetrics(0) // 2, ctypes.windll.user32.GetSystemMetrics(1) // 2),
delay_time=0, note: Union[str, List[str]] = None, **options):
if isinstance(img_list, np.ndarray):
img_list = [img_list]
if isinstance(note, str):
print(note)
cv2.namedWindow(window_name, cv2.WINDOW_NORMAL)
if window_size:
w, h = window_size
cv2.resizeWindow(window_name, w, h)
result_list = []
for idx, img in enumerate(img_list):
img = np.copy(img)
if note and isinstance(note, list) and idx < len(note):
cv2.putText(img, note[idx], org=options.get('org', (50, 50)),
fontFace=options.get('fontFace', cv2.FONT_HERSHEY_SIMPLEX),
fontScale=options.get('fontScale', 2), color=(0, 255, 255), thickness=4)
result_list.append(img)
cv2.imshow(window_name, combine_fun(result_list))
cv2.waitKey(delay_time)
control_bar_hsv.py
使用起来很简单,只需复制粘贴然后告诉它你的图片路径在哪里,就完成了。
如果你想创建其他control_bar,也许ControlBarBase
会帮助你写更少的代码。
"""
control_bar_hsv.py
"""
import cv2
from pathlib import Path
import numpy as np
import ctypes
import functools
from typing import Tuple, Callable
class ControlBarBase:
__slots__ = ('img_bgr',)
WAIT_TIME = 500 # milliseconds
CONTROL_PANEL_NAME = 'control_panel'
IMAGE_PANEL_NAME = 'image'
SCREEN_SIZE: Tuple[int, int] = None
def __init__(self, img_path: Path):
self.img_bgr: np.ndarray = cv2.imread(str(img_path))
self.init_window()
self.init_track_bar()
def init_window(self):
for name in (self.CONTROL_PANEL_NAME, self.IMAGE_PANEL_NAME):
cv2.namedWindow(name, cv2.WINDOW_NORMAL)
if self.SCREEN_SIZE:
screen_width, screen_height = self.SCREEN_SIZE
cv2.resizeWindow(name, int(screen_width), int(screen_height))
def init_track_bar(self):
"""
self.build_track_bar(label_name, range_lim=(0, 255), default_value=0, callback)
"""
raise NotImplementedError('subclasses of _ControlBarBase must provide a init_track_bar() method')
def render(self):
raise NotImplementedError('subclasses of _ControlBarBase must provide a render() method.')
def build_track_bar(self, label_name: str,
range_lim: Tuple[int, int], default_value: int, callback: Callable = lambda x: ...):
min_val, max_val = range_lim
cv2.createTrackbar(label_name, self.CONTROL_PANEL_NAME, min_val, max_val, callback)
cv2.setTrackbarPos(label_name, self.CONTROL_PANEL_NAME, default_value)
def get_trackbar_pos(self, widget_name: str):
return cv2.getTrackbarPos(widget_name, self.CONTROL_PANEL_NAME)
def run(self):
while 1:
img, callback_func = self.render()
cv2.imshow(self.IMAGE_PANEL_NAME, img)
if (cv2.waitKey(self.WAIT_TIME) & 0xFF == ord('q') or
cv2.getWindowProperty(self.IMAGE_PANEL_NAME, 0) == -1 or
cv2.getWindowProperty(self.CONTROL_PANEL_NAME, 0) == -1):
callback_func()
break
cv2.destroyAllWindows()
class ControlBarHSV(ControlBarBase):
__slots__ = ()
WAIT_TIME = 500
SCREEN_SIZE = ctypes.windll.user32.GetSystemMetrics(0) / 2, ctypes.windll.user32.GetSystemMetrics(1) / 2
def init_track_bar(self):
self.build_track_bar('HMin', range_lim=(0, 179), default_value=0)
self.build_track_bar('SMin', (0, 255), 0)
self.build_track_bar('VMin', (0, 255), 0)
self.build_track_bar('HMax', (0, 179), 179)
self.build_track_bar('SMax', (0, 255), 255)
self.build_track_bar('VMax', (0, 255), 255)
def render(self):
# get current positions of all trackbars
h_min = self.get_trackbar_pos('HMin')
s_min = self.get_trackbar_pos('SMin')
v_min = self.get_trackbar_pos('VMin')
h_max = self.get_trackbar_pos('HMax')
s_max = self.get_trackbar_pos('SMax')
v_max = self.get_trackbar_pos('VMax')
# Set minimum and max HSV values to display
lower = np.array([h_min, s_min, v_min])
upper = np.array([h_max, s_max, v_max])
# Create HSV Image and threshold into a range.
hsv = cv2.cvtColor(self.img_bgr, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, lower, upper)
img_output: np.ndarray = cv2.bitwise_and(self.img_bgr, self.img_bgr, mask=mask)
@functools.wraps(self.render)
def cb_func():
return print(f'cv2.inRange(src=hsv, lowerb=np.array([{h_min}, {s_min}, {v_min}]), upperb=np.array([{h_max}, {s_max}, {v_max}]))')
return img_output, cb_func
if __name__ == '__main__':
from argparse import ArgumentParser
arg_parser = ArgumentParser()
arg_parser.add_argument("src_path", type=Path, help="source image path")
args = arg_parser.parse_args()
obj = ControlBarHSV(args.src_path) # ControlBarHSV(Path('parking.jpg'))
obj.run()