chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:06:04 +08:00
commit 86c9b1c39f
7743 changed files with 3316339 additions and 0 deletions
+10
View File
@@ -0,0 +1,10 @@
# python binary files
*.pyc
__pycache__
# tmp files from examples
/output
*.dat
out.ply
svm_scores.npz
unused_api.txt
+6
View File
@@ -0,0 +1,6 @@
if(INSTALL_PYTHON_EXAMPLES)
file(GLOB install_list *.py )
install(FILES ${install_list}
DESTINATION ${OPENCV_SAMPLES_SRC_INSTALL_PATH}/python
PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples)
endif()
+29
View File
@@ -0,0 +1,29 @@
#!/usr/bin/env python
'''
Utility for measuring python opencv API coverage by samples.
'''
# Python 2/3 compatibility
from __future__ import print_function
from glob import glob
import cv2 as cv
import re
if __name__ == '__main__':
cv2_callable = set(['cv.'+name for name in dir(cv) if callable( getattr(cv, name) )])
found = set()
for fn in glob('*.py'):
print(' --- ', fn)
code = open(fn).read()
found |= set(re.findall(r'cv2?\.\w+', code))
cv2_used = found & cv2_callable
cv2_unused = cv2_callable - cv2_used
with open('unused_api.txt', 'w') as f:
f.write('\n'.join(sorted(cv2_unused)))
r = 1.0 * len(cv2_used) / len(cv2_callable)
print('\ncv api coverage: %d / %d (%.1f%%)' % ( len(cv2_used), len(cv2_callable), r*100 ))
+25
View File
@@ -0,0 +1,25 @@
#!/usr/bin/env python
'''
Scans current directory for *.py files and reports
ones with missing __doc__ string.
'''
# Python 2/3 compatibility
from __future__ import print_function
from glob import glob
if __name__ == '__main__':
print('--- undocumented files:')
for fn in glob('*.py'):
loc = {}
try:
try:
execfile(fn, loc) # Python 2
except NameError:
exec(open(fn).read(), loc) # Python 3
except Exception:
pass
if '__doc__' not in loc:
print(fn)
+3
View File
@@ -0,0 +1,3 @@
@echo off
call ..\_winpack_run_python_sample.cmd %*
exit /B
@@ -0,0 +1,116 @@
#!/usr/bin/env python
"""aruco_detect_board_charuco.py
Usage example:
python aruco_detect_board_charuco.py -w=5 -h=7 -sl=0.04 -ml=0.02 -d=10 -c=../data/aruco/tutorial_camera_charuco.yml
-i=../data/aruco/choriginal.jpg
"""
import argparse
import numpy as np
import cv2 as cv
import sys
def read_camera_parameters(filename):
fs = cv.FileStorage(cv.samples.findFile(filename, False), cv.FileStorage_READ)
if fs.isOpened():
cam_matrix = fs.getNode("camera_matrix").mat()
dist_coefficients = fs.getNode("distortion_coefficients").mat()
return True, cam_matrix, dist_coefficients
return False, [], []
def main():
# parse command line options
parser = argparse.ArgumentParser(description="detect markers and corners of charuco board, estimate pose of charuco"
"board", add_help=False)
parser.add_argument("-H", "--help", help="show help", action="store_true", dest="show_help")
parser.add_argument("-v", "--video", help="Input from video or image file, if omitted, input comes from camera",
default="", action="store", dest="v")
parser.add_argument("-i", "--image", help="Input from image file", default="", action="store", dest="img_path")
parser.add_argument("-w", help="Number of squares in X direction", default="3", action="store", dest="w", type=int)
parser.add_argument("-h", help="Number of squares in Y direction", default="3", action="store", dest="h", type=int)
parser.add_argument("-sl", help="Square side length", default="1.", action="store", dest="sl", type=float)
parser.add_argument("-ml", help="Marker side length", default="0.5", action="store", dest="ml", type=float)
parser.add_argument("-d", help="dictionary: DICT_4X4_50=0, DICT_4X4_100=1, DICT_4X4_250=2, DICT_4X4_1000=3,"
"DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, DICT_6X6_50=8,"
"DICT_6X6_100=9, DICT_6X6_250=10, DICT_6X6_1000=11, DICT_7X7_50=12, DICT_7X7_100=13,"
"DICT_7X7_250=14, DICT_7X7_1000=15, DICT_ARUCO_ORIGINAL=16,"
"DICT_APRILTAG_16h5=17, DICT_APRILTAG_25h9=18, DICT_APRILTAG_36h10=19, DICT_APRILTAG_36h11=20, DICT_ARUCO_MIP_36h12=21}",
default="0", action="store", dest="d", type=int)
parser.add_argument("-ci", help="Camera id if input doesnt come from video (-v)", default="0", action="store",
dest="ci", type=int)
parser.add_argument("-c", help="Input file with calibrated camera parameters", default="", action="store",
dest="cam_param")
args = parser.parse_args()
show_help = args.show_help
if show_help:
parser.print_help()
sys.exit()
width = args.w
height = args.h
square_len = args.sl
marker_len = args.ml
dict = args.d
video = args.v
camera_id = args.ci
img_path = args.img_path
cam_param = args.cam_param
cam_matrix = []
dist_coefficients = []
if cam_param != "":
_, cam_matrix, dist_coefficients = read_camera_parameters(cam_param)
aruco_dict = cv.aruco.getPredefinedDictionary(dict)
board_size = (width, height)
board = cv.aruco.CharucoBoard(board_size, square_len, marker_len, aruco_dict)
charuco_detector = cv.aruco.CharucoDetector(board)
image = None
input_video = None
wait_time = 10
if video != "":
input_video = cv.VideoCapture(cv.samples.findFileOrKeep(video, False))
image = input_video.retrieve()[1] if input_video.grab() else None
elif img_path == "":
input_video = cv.VideoCapture(camera_id)
image = input_video.retrieve()[1] if input_video.grab() else None
elif img_path != "":
wait_time = 0
image = cv.imread(cv.samples.findFile(img_path, False))
if image is None:
print("Error: unable to open video/image source")
sys.exit(0)
while image is not None:
image_copy = np.copy(image)
charuco_corners, charuco_ids, marker_corners, marker_ids = charuco_detector.detectBoard(image)
if not (marker_ids is None) and len(marker_ids) > 0:
cv.aruco.drawDetectedMarkers(image_copy, marker_corners)
if not (charuco_ids is None) and len(charuco_ids) > 0:
cv.aruco.drawDetectedCornersCharuco(image_copy, charuco_corners, charuco_ids)
if len(cam_matrix) > 0 and len(charuco_ids) >= 4:
try:
obj_points, img_points = board.matchImagePoints(charuco_corners, charuco_ids)
flag, rvec, tvec = cv.solvePnP(obj_points, img_points, cam_matrix, dist_coefficients)
if flag:
cv.drawFrameAxes(image_copy, cam_matrix, dist_coefficients, rvec, tvec, .2)
except cv.error as error_inst:
print("SolvePnP recognize calibration pattern as non-planar pattern. To process this need to use "
"minimum 6 points. The planar pattern may be mistaken for non-planar if the pattern is "
"deformed or incorrect camera parameters are used.")
print(error_inst.err)
cv.imshow("out", image_copy)
key = cv.waitKey(wait_time)
if key == 27:
break
image = input_video.retrieve()[1] if input_video is not None and input_video.grab() else None
if __name__ == "__main__":
main()
+168
View File
@@ -0,0 +1,168 @@
#!/usr/bin/env python
'''
Affine invariant feature-based image matching sample.
This sample is similar to find_obj.py, but uses the affine transformation
space sampling technique, called ASIFT [1]. While the original implementation
is based on SIFT, you can try to use SURF or ORB detectors instead. Homography RANSAC
is used to reject outliers. Threading is used for faster affine sampling.
[1] http://www.ipol.im/pub/algo/my_affine_sift/
USAGE
asift.py [--feature=<sift|surf|orb|brisk>[-flann]] [ <image1> <image2> ]
--feature - Feature to use. Can be sift, surf, orb or brisk. Append '-flann'
to feature name to use Flann-based matcher instead bruteforce.
Press left mouse button on a feature point to see its matching point.
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
# built-in modules
import itertools as it
from multiprocessing.pool import ThreadPool
# local modules
from common import Timer
from find_obj import init_feature, filter_matches, explore_match
def affine_skew(tilt, phi, img, mask=None):
'''
affine_skew(tilt, phi, img, mask=None) -> skew_img, skew_mask, Ai
Ai - is an affine transform matrix from skew_img to img
'''
h, w = img.shape[:2]
if mask is None:
mask = np.zeros((h, w), np.uint8)
mask[:] = 255
A = np.float32([[1, 0, 0], [0, 1, 0]])
if phi != 0.0:
phi = np.deg2rad(phi)
s, c = np.sin(phi), np.cos(phi)
A = np.float32([[c,-s], [ s, c]])
corners = [[0, 0], [w, 0], [w, h], [0, h]]
tcorners = np.int32( np.dot(corners, A.T) )
x, y, w, h = cv.boundingRect(tcorners.reshape(1,-1,2))
A = np.hstack([A, [[-x], [-y]]])
img = cv.warpAffine(img, A, (w, h), flags=cv.INTER_LINEAR, borderMode=cv.BORDER_REPLICATE)
if tilt != 1.0:
s = 0.8*np.sqrt(tilt*tilt-1)
img = cv.GaussianBlur(img, (0, 0), sigmaX=s, sigmaY=0.01)
img = cv.resize(img, (0, 0), fx=1.0/tilt, fy=1.0, interpolation=cv.INTER_NEAREST)
A[0] /= tilt
if phi != 0.0 or tilt != 1.0:
h, w = img.shape[:2]
mask = cv.warpAffine(mask, A, (w, h), flags=cv.INTER_NEAREST)
Ai = cv.invertAffineTransform(A)
return img, mask, Ai
def affine_detect(detector, img, mask=None, pool=None):
'''
affine_detect(detector, img, mask=None, pool=None) -> keypoints, descrs
Apply a set of affine transformations to the image, detect keypoints and
reproject them into initial image coordinates.
See http://www.ipol.im/pub/algo/my_affine_sift/ for the details.
ThreadPool object may be passed to speedup the computation.
'''
params = [(1.0, 0.0)]
for t in 2**(0.5*np.arange(1,6)):
for phi in np.arange(0, 180, 72.0 / t):
params.append((t, phi))
def f(p):
t, phi = p
timg, tmask, Ai = affine_skew(t, phi, img)
keypoints, descrs = detector.detectAndCompute(timg, tmask)
for kp in keypoints:
x, y = kp.pt
kp.pt = tuple( np.dot(Ai, (x, y, 1)) )
if descrs is None:
descrs = []
return keypoints, descrs
keypoints, descrs = [], []
if pool is None:
ires = it.imap(f, params)
else:
ires = pool.imap(f, params)
for i, (k, d) in enumerate(ires):
print('affine sampling: %d / %d\r' % (i+1, len(params)), end='')
keypoints.extend(k)
descrs.extend(d)
print()
return keypoints, np.array(descrs)
def main():
import sys, getopt
opts, args = getopt.getopt(sys.argv[1:], '', ['feature='])
opts = dict(opts)
feature_name = opts.get('--feature', 'brisk-flann')
try:
fn1, fn2 = args
except:
fn1 = 'aero1.jpg'
fn2 = 'aero3.jpg'
img1 = cv.imread(cv.samples.findFile(fn1), cv.IMREAD_GRAYSCALE)
img2 = cv.imread(cv.samples.findFile(fn2), cv.IMREAD_GRAYSCALE)
detector, matcher = init_feature(feature_name)
if img1 is None:
print('Failed to load fn1:', fn1)
sys.exit(1)
if img2 is None:
print('Failed to load fn2:', fn2)
sys.exit(1)
if detector is None:
print('unknown feature:', feature_name)
sys.exit(1)
print('using', feature_name)
pool=ThreadPool(processes = cv.getNumberOfCPUs())
kp1, desc1 = affine_detect(detector, img1, pool=pool)
kp2, desc2 = affine_detect(detector, img2, pool=pool)
print('img1 - %d features, img2 - %d features' % (len(kp1), len(kp2)))
def match_and_draw(win):
with Timer('matching'):
raw_matches = matcher.knnMatch(desc1, trainDescriptors = desc2, k = 2) #2
p1, p2, kp_pairs = filter_matches(kp1, kp2, raw_matches)
if len(p1) >= 4:
H, status = cv.findHomography(p1, p2, cv.RANSAC, 5.0)
print('%d / %d inliers/matched' % (np.sum(status), len(status)))
# do not draw outliers (there will be a lot of them)
kp_pairs = [kpp for kpp, flag in zip(kp_pairs, status) if flag]
else:
H, status = None, None
print('%d matches found, not enough for homography estimation' % len(p1))
explore_match(win, img1, img2, kp_pairs, None, H)
match_and_draw('affine find_obj')
cv.waitKey()
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+808
View File
@@ -0,0 +1,808 @@
import numpy as np
import cv2 as cv
import math
import argparse
class AudioDrawing:
'''
Used for drawing audio graphics
'''
def __init__(self, args):
self.inputType = args.inputType
self.draw = args.draw
self.graph = args.graph
self.audio = cv.samples.findFile(args.audio)
self.audioStream = args.audioStream
self.windowType = args.windowType
self.windLen = args.windLen
self.overlap = args.overlap
self.enableGrid = args.enableGrid
self.rows = args.rows
self.cols = args.cols
self.xmarkup = args.xmarkup
self.ymarkup = args.ymarkup
self.zmarkup = args.zmarkup
self.microTime = args.microTime
self.frameSizeTime = args.frameSizeTime
self.updateTime = args.updateTime
self.waitTime = args.waitTime
if self.initAndCheckArgs(args) is False:
exit()
def Draw(self):
if self.draw == "static":
if self.inputType == "file":
samplingRate, inputAudio = self.readAudioFile(self.audio)
elif self.inputType == "microphone":
samplingRate, inputAudio = self.readAudioMicrophone()
duration = len(inputAudio) // samplingRate
# since the dimensional grid is counted in integer seconds,
# if the input audio has an incomplete last second,
# then it is filled with zeros to complete
remainder = len(inputAudio) % samplingRate
if remainder != 0:
sizeToFullSec = samplingRate - remainder
zeroArr = np.zeros(sizeToFullSec)
inputAudio = np.concatenate((inputAudio, zeroArr), axis=0)
duration += 1
print("Update duration of audio to full second with ",
sizeToFullSec, " zero samples")
print("New number of samples ", len(inputAudio))
if duration <= self.xmarkup:
self.xmarkup = duration + 1
if self.graph == "ampl":
imgAmplitude = self.drawAmplitude(inputAudio)
imgAmplitude = self.drawAmplitudeScale(imgAmplitude, inputAudio, samplingRate)
cv.imshow("Display window", imgAmplitude)
cv.waitKey(0)
elif self.graph == "spec":
stft = self.STFT(inputAudio)
imgSpec = self.drawSpectrogram(stft)
imgSpec = self.drawSpectrogramColorbar(imgSpec, inputAudio, samplingRate, stft)
cv.imshow("Display window", imgSpec)
cv.waitKey(0)
elif self.graph == "ampl_and_spec":
imgAmplitude = self.drawAmplitude(inputAudio)
imgAmplitude = self.drawAmplitudeScale(imgAmplitude, inputAudio, samplingRate)
stft = self.STFT(inputAudio)
imgSpec = self.drawSpectrogram(stft)
imgSpec = self.drawSpectrogramColorbar(imgSpec, inputAudio, samplingRate, stft)
imgTotal = self.concatenateImages(imgAmplitude, imgSpec)
cv.imshow("Display window", imgTotal)
cv.waitKey(0)
elif self.draw == "dynamic":
if self.inputType == "file":
self.dynamicFile(self.audio)
elif self.inputType == "microphone":
self.dynamicMicrophone()
def readAudioFile(self, file):
cap = cv.VideoCapture(file)
params = [cv.CAP_PROP_AUDIO_STREAM, self.audioStream,
cv.CAP_PROP_VIDEO_STREAM, -1,
cv.CAP_PROP_AUDIO_DATA_DEPTH, cv.CV_16S]
params = np.asarray(params)
cap.open(file, cv.CAP_ANY, params)
if cap.isOpened() == False:
print("Error : Can't read audio file: '", self.audio, "' with audioStream = ", self.audioStream)
print("Error: problems with audio reading, check input arguments")
exit()
audioBaseIndex = int(cap.get(cv.CAP_PROP_AUDIO_BASE_INDEX))
numberOfChannels = int(cap.get(cv.CAP_PROP_AUDIO_TOTAL_CHANNELS))
print("CAP_PROP_AUDIO_DATA_DEPTH: ", str((int(cap.get(cv.CAP_PROP_AUDIO_DATA_DEPTH)))))
print("CAP_PROP_AUDIO_SAMPLES_PER_SECOND: ", cap.get(cv.CAP_PROP_AUDIO_SAMPLES_PER_SECOND))
print("CAP_PROP_AUDIO_TOTAL_CHANNELS: ", numberOfChannels)
print("CAP_PROP_AUDIO_TOTAL_STREAMS: ", cap.get(cv.CAP_PROP_AUDIO_TOTAL_STREAMS))
frame = []
frame = np.asarray(frame)
inputAudio = []
while (1):
if (cap.grab()):
frame = []
frame = np.asarray(frame)
frame = cap.retrieve(frame, audioBaseIndex)
for i in range(len(frame[1][0])):
inputAudio.append(frame[1][0][i])
else:
break
inputAudio = np.asarray(inputAudio)
print("Number of samples: ", len(inputAudio))
samplingRate = int(cap.get(cv.CAP_PROP_AUDIO_SAMPLES_PER_SECOND))
return samplingRate, inputAudio
def readAudioMicrophone(self):
cap = cv.VideoCapture()
params = [cv.CAP_PROP_AUDIO_STREAM, 0, cv.CAP_PROP_VIDEO_STREAM, -1]
params = np.asarray(params)
cap.open(0, cv.CAP_ANY, params)
if cap.isOpened() == False:
print("Error: Can't open microphone")
print("Error: problems with audio reading, check input arguments")
exit()
audioBaseIndex = int(cap.get(cv.CAP_PROP_AUDIO_BASE_INDEX))
numberOfChannels = int(cap.get(cv.CAP_PROP_AUDIO_TOTAL_CHANNELS))
print("CAP_PROP_AUDIO_DATA_DEPTH: ", str((int(cap.get(cv.CAP_PROP_AUDIO_DATA_DEPTH)))))
print("CAP_PROP_AUDIO_SAMPLES_PER_SECOND: ", cap.get(cv.CAP_PROP_AUDIO_SAMPLES_PER_SECOND))
print("CAP_PROP_AUDIO_TOTAL_CHANNELS: ", numberOfChannels)
print("CAP_PROP_AUDIO_TOTAL_STREAMS: ", cap.get(cv.CAP_PROP_AUDIO_TOTAL_STREAMS))
cvTickFreq = cv.getTickFrequency()
sysTimeCurr = cv.getTickCount()
sysTimePrev = sysTimeCurr
frame = []
frame = np.asarray(frame)
inputAudio = []
while ((sysTimeCurr - sysTimePrev) / cvTickFreq < self.microTime):
if (cap.grab()):
frame = []
frame = np.asarray(frame)
frame = cap.retrieve(frame, audioBaseIndex)
for i in range(len(frame[1][0])):
inputAudio.append(frame[1][0][i])
sysTimeCurr = cv.getTickCount()
else:
print("Error: Grab error")
break
inputAudio = np.asarray(inputAudio)
print("Number of samples: ", len(inputAudio))
samplingRate = int(cap.get(cv.CAP_PROP_AUDIO_SAMPLES_PER_SECOND))
return samplingRate, inputAudio
def drawAmplitude(self, inputAudio):
color = (247, 111, 87)
thickness = 5
frameVectorRows = 500
middle = frameVectorRows // 2
# usually the input data is too big, so it is necessary
# to reduce size using interpolation of data
frameVectorCols = 40000
if len(inputAudio) < frameVectorCols:
frameVectorCols = len(inputAudio)
img = np.zeros((frameVectorRows, frameVectorCols, 3), np.uint8)
img += 255 # white background
audio = np.array(0)
audio = cv.resize(inputAudio, (1, frameVectorCols), interpolation=cv.INTER_LINEAR)
reshapeAudio = np.reshape(audio, (-1))
# normalization data by maximum element
minCv, maxCv, _, _ = cv.minMaxLoc(reshapeAudio)
maxElem = int(max(abs(minCv), abs(maxCv)))
# if all data values are zero (silence)
if maxElem == 0:
maxElem = 1
for i in range(len(reshapeAudio)):
reshapeAudio[i] = middle - reshapeAudio[i] * middle // maxElem
for i in range(1, frameVectorCols, 1):
cv.line(img, (i - 1, int(reshapeAudio[i - 1])), (i, int(reshapeAudio[i])), color, thickness)
img = cv.resize(img, (900, 400), interpolation=cv.INTER_AREA)
return img
def drawAmplitudeScale(self, inputImg, inputAudio, samplingRate, xmin=None, xmax=None):
# function of layout drawing for graph of volume amplitudes
# x axis for time
# y axis for amplitudes
# parameters for the new image size
preCol = 100
aftCol = 100
preLine = 40
aftLine = 50
frameVectorRows = inputImg.shape[0]
frameVectorCols = inputImg.shape[1]
totalRows = preLine + frameVectorRows + aftLine
totalCols = preCol + frameVectorCols + aftCol
imgTotal = np.zeros((totalRows, totalCols, 3), np.uint8)
imgTotal += 255 # white background
imgTotal[preLine: preLine + frameVectorRows, preCol: preCol + frameVectorCols] = inputImg
# calculating values on x axis
if xmin is None:
xmin = 0
if xmax is None:
xmax = len(inputAudio) / samplingRate
if xmax > self.xmarkup:
xList = np.linspace(xmin, xmax, self.xmarkup).astype(int)
else:
# this case is used to display a dynamic update
tmp = np.arange(xmin, xmax, 1).astype(int) + 1
xList = np.concatenate((np.zeros(self.xmarkup - len(tmp)), tmp[:]), axis=None)
# calculating values on y axis
ymin = np.min(inputAudio)
ymax = np.max(inputAudio)
yList = np.linspace(ymin, ymax, self.ymarkup)
# parameters for layout drawing
textThickness = 1
gridThickness = 1
gridColor = (0, 0, 0)
textColor = (0, 0, 0)
font = cv.FONT_HERSHEY_SIMPLEX
fontScale = 0.5
# horizontal axis under the graph
cv.line(imgTotal, (preCol, totalRows - aftLine),
(preCol + frameVectorCols, totalRows - aftLine),
gridColor, gridThickness)
# vertical axis for amplitude
cv.line(imgTotal, (preCol, preLine), (preCol, preLine + frameVectorRows),
gridColor, gridThickness)
# parameters for layout calculation
serifSize = 10
indentDownX = serifSize * 2
indentDownY = serifSize // 2
indentLeftX = serifSize
indentLeftY = 2 * preCol // 3
# drawing layout for x axis
numX = frameVectorCols // (self.xmarkup - 1)
for i in range(len(xList)):
a1 = preCol + i * numX
a2 = frameVectorRows + preLine
b1 = a1
b2 = a2 + serifSize
if self.enableGrid is True:
d1 = a1
d2 = preLine
cv.line(imgTotal, (a1, a2), (d1, d2), gridColor, gridThickness)
cv.line(imgTotal, (a1, a2), (b1, b2), gridColor, gridThickness)
cv.putText(imgTotal, str(int(xList[i])), (b1 - indentLeftX, b2 + indentDownX),
font, fontScale, textColor, textThickness)
# drawing layout for y axis
numY = frameVectorRows // (self.ymarkup - 1)
for i in range(len(yList)):
a1 = preCol
a2 = totalRows - aftLine - i * numY
b1 = preCol - serifSize
b2 = a2
if self.enableGrid is True:
d1 = preCol + frameVectorCols
d2 = a2
cv.line(imgTotal, (a1, a2), (d1, d2), gridColor, gridThickness)
cv.line(imgTotal, (a1, a2), (b1, b2), gridColor, gridThickness)
cv.putText(imgTotal, str(int(yList[i])), (b1 - indentLeftY, b2 + indentDownY),
font, fontScale, textColor, textThickness)
imgTotal = cv.resize(imgTotal, (self.cols, self.rows), interpolation=cv.INTER_AREA)
return imgTotal
def STFT(self, inputAudio):
"""
The Short-time Fourier transform (STFT), is a Fourier-related transform used to determine
the sinusoidal frequency and phase content of local sections of a signal as it changes over
time.
In practice, the procedure for computing STFTs is to divide a longer time signal into
shorter segments of equal length and then compute the Fourier transform separately on each
shorter segment. This reveals the Fourier spectrum on each shorter segment. One then usually
plots the changing spectra as a function of time, known as a spectrogram or waterfall plot.
https://en.wikipedia.org/wiki/Short-time_Fourier_transform
"""
time_step = self.windLen - self.overlap
if time_step <= 0:
raise ValueError(
"Invalid STFT parameters: overlap must be smaller than window length"
)
stft = []
if self.windowType == "Hann":
# https://en.wikipedia.org/wiki/Window_function#Hann_and_Hamming_windows
Hann_wind = []
for i in range (1 - self.windLen, self.windLen, 2):
Hann_wind.append(i * (0.5 + 0.5 * math.cos(math.pi * i / (self.windLen - 1))))
Hann_wind = np.asarray(Hann_wind)
elif self.windowType == "Hamming":
# https://en.wikipedia.org/wiki/Window_function#Hann_and_Hamming_windows
Hamming_wind = []
for i in range (1 - self.windLen, self.windLen, 2):
Hamming_wind.append(i * (0.53836 - 0.46164 * (math.cos(2 * math.pi * i / (self.windLen - 1)))))
Hamming_wind = np.asarray(Hamming_wind)
for index in np.arange(0, len(inputAudio), time_step).astype(int):
section = inputAudio[index:index + self.windLen]
zeroArray = np.zeros(self.windLen - len(section))
section = np.concatenate((section, zeroArray), axis=None)
if self.windowType == "Hann":
section *= Hann_wind
elif self.windowType == "Hamming":
section *= Hamming_wind
dst = np.empty(0)
dst = cv.dft(section, dst, flags=cv.DFT_COMPLEX_OUTPUT)
reshape_dst = np.reshape(dst, (-1))
# we need only the first part of the spectrum, the second part is symmetrical
complexArr = np.zeros(len(dst) // 4, dtype=complex)
for i in range(len(dst) // 4):
complexArr[i] = complex(reshape_dst[2 * i], reshape_dst[2 * i + 1])
stft.append(np.abs(complexArr))
stft = np.array(stft).transpose()
# convert elements to the decibel scale
np.log10(stft, out=stft, where=(stft != 0.))
return 10 * stft
def drawSpectrogram(self, stft):
frameVectorRows = stft.shape[0]
frameVectorCols = stft.shape[1]
# Normalization of image values from 0 to 255 to get more contrast image
# and this normalization will be taken into account in the scale drawing
colormapImageRows = 255
imgSpec = np.zeros((frameVectorRows, frameVectorCols, 3), np.uint8)
stftMat = np.zeros((frameVectorRows, frameVectorCols), np.float64)
cv.normalize(stft, stftMat, 1.0, 0.0, cv.NORM_INF)
for i in range(frameVectorRows):
for j in range(frameVectorCols):
imgSpec[frameVectorRows - i - 1, j] = int(stftMat[i][j] * colormapImageRows)
imgSpec = cv.applyColorMap(imgSpec, cv.COLORMAP_INFERNO)
imgSpec = cv.resize(imgSpec, (900, 400), interpolation=cv.INTER_LINEAR)
return imgSpec
def drawSpectrogramColorbar(self, inputImg, inputAudio, samplingRate, stft, xmin=None, xmax=None):
# function of layout drawing for the three-dimensional graph of the spectrogram
# x axis for time
# y axis for frequencies
# z axis for magnitudes of frequencies shown by color scale
# parameters for the new image size
preCol = 100
aftCol = 100
preLine = 40
aftLine = 50
colColor = 20
ind_col = 20
frameVectorRows = inputImg.shape[0]
frameVectorCols = inputImg.shape[1]
totalRows = preLine + frameVectorRows + aftLine
totalCols = preCol + frameVectorCols + aftCol + colColor
imgTotal = np.zeros((totalRows, totalCols, 3), np.uint8)
imgTotal += 255 # white background
imgTotal[preLine: preLine + frameVectorRows, preCol: preCol + frameVectorCols] = inputImg
# colorbar image due to drawSpectrogram(..) picture has been normalised from 255 to 0,
# so here colorbar has values from 255 to 0
colorArrSize = 256
imgColorBar = np.zeros((colorArrSize, colColor, 1), np.uint8)
for i in range(colorArrSize):
imgColorBar[i] += colorArrSize - 1 - i
imgColorBar = cv.applyColorMap(imgColorBar, cv.COLORMAP_INFERNO)
imgColorBar = cv.resize(imgColorBar, (colColor, frameVectorRows), interpolation=cv.INTER_AREA) #
imgTotal[preLine: preLine + frameVectorRows,
preCol + frameVectorCols + ind_col:
preCol + frameVectorCols + ind_col + colColor] = imgColorBar
# calculating values on x axis
if xmin is None:
xmin = 0
if xmax is None:
xmax = len(inputAudio) / samplingRate
if xmax > self.xmarkup:
xList = np.linspace(xmin, xmax, self.xmarkup).astype(int)
else:
# this case is used to display a dynamic update
tmpXList = np.arange(xmin, xmax, 1).astype(int) + 1
xList = np.concatenate((np.zeros(self.xmarkup - len(tmpXList)), tmpXList[:]), axis=None)
# calculating values on y axis
# according to the Nyquist sampling theorem,
# signal should posses frequencies equal to half of sampling rate
ymin = 0
ymax = int(samplingRate / 2.)
yList = np.linspace(ymin, ymax, self.ymarkup).astype(int)
# calculating values on z axis
zList = np.linspace(np.min(stft), np.max(stft), self.zmarkup)
# parameters for layout drawing
textThickness = 1
textColor = (0, 0, 0)
gridThickness = 1
gridColor = (0, 0, 0)
font = cv.FONT_HERSHEY_SIMPLEX
fontScale = 0.5
serifSize = 10
indentDownX = serifSize * 2
indentDownY = serifSize // 2
indentLeftX = serifSize
indentLeftY = 2 * preCol // 3
# horizontal axis
cv.line(imgTotal, (preCol, totalRows - aftLine), (preCol + frameVectorCols, totalRows - aftLine),
gridColor, gridThickness)
# vertical axis
cv.line(imgTotal, (preCol, preLine), (preCol, preLine + frameVectorRows),
gridColor, gridThickness)
# drawing layout for x axis
numX = frameVectorCols // (self.xmarkup - 1)
for i in range(len(xList)):
a1 = preCol + i * numX
a2 = frameVectorRows + preLine
b1 = a1
b2 = a2 + serifSize
cv.line(imgTotal, (a1, a2), (b1, b2), gridColor, gridThickness)
cv.putText(imgTotal, str(int(xList[i])), (b1 - indentLeftX, b2 + indentDownX),
font, fontScale, textColor, textThickness)
# drawing layout for y axis
numY = frameVectorRows // (self.ymarkup - 1)
for i in range(len(yList)):
a1 = preCol
a2 = totalRows - aftLine - i * numY
b1 = preCol - serifSize
b2 = a2
cv.line(imgTotal, (a1, a2), (b1, b2), gridColor, gridThickness)
cv.putText(imgTotal, str(int(yList[i])), (b1 - indentLeftY, b2 + indentDownY),
font, fontScale, textColor, textThickness)
# drawing layout for z axis
numZ = frameVectorRows // (self.zmarkup - 1)
for i in range(len(zList)):
a1 = preCol + frameVectorCols + ind_col + colColor
a2 = totalRows - aftLine - i * numZ
b1 = a1 + serifSize
b2 = a2
cv.line(imgTotal, (a1, a2), (b1, b2), gridColor, gridThickness)
cv.putText(imgTotal, str(int(zList[i])), (b1 + 10, b2 + indentDownY),
font, fontScale, textColor, textThickness)
imgTotal = cv.resize(imgTotal, (self.cols, self.rows), interpolation=cv.INTER_AREA)
return imgTotal
def concatenateImages(self, img1, img2):
# first image will be under the second image
totalRows = img1.shape[0] + img2.shape[0]
totalCols = max(img1.shape[1], img2.shape[1])
# if images columns do not match, the difference is filled in white
imgTotal = np.zeros((totalRows, totalCols, 3), np.uint8)
imgTotal += 255
imgTotal[:img1.shape[0], :img1.shape[1]] = img1
imgTotal[img2.shape[0]:, :img2.shape[1]] = img2
return imgTotal
def dynamicFile(self, file):
cap = cv.VideoCapture(file)
params = [cv.CAP_PROP_AUDIO_STREAM, self.audioStream,
cv.CAP_PROP_VIDEO_STREAM, -1,
cv.CAP_PROP_AUDIO_DATA_DEPTH, cv.CV_16S]
params = np.asarray(params)
cap.open(file, cv.CAP_ANY, params)
if cap.isOpened() == False:
print("ERROR! Can't to open file")
return
audioBaseIndex = int(cap.get(cv.CAP_PROP_AUDIO_BASE_INDEX))
numberOfChannels = int(cap.get(cv.CAP_PROP_AUDIO_TOTAL_CHANNELS))
samplingRate = int(cap.get(cv.CAP_PROP_AUDIO_SAMPLES_PER_SECOND))
print("CAP_PROP_AUDIO_DATA_DEPTH: ", str((int(cap.get(cv.CAP_PROP_AUDIO_DATA_DEPTH)))))
print("CAP_PROP_AUDIO_SAMPLES_PER_SECOND: ", cap.get(cv.CAP_PROP_AUDIO_SAMPLES_PER_SECOND))
print("CAP_PROP_AUDIO_TOTAL_CHANNELS: ", numberOfChannels)
print("CAP_PROP_AUDIO_TOTAL_STREAMS: ", cap.get(cv.CAP_PROP_AUDIO_TOTAL_STREAMS))
step = int(self.updateTime * samplingRate)
frameSize = int(self.frameSizeTime * samplingRate)
# since the dimensional grid is counted in integer seconds,
# if duration of audio frame is less than xmarkup, to avoid an incorrect display,
# xmarkup will be taken equal to duration
if self.frameSizeTime <= self.xmarkup:
self.xmarkup = self.frameSizeTime
buffer = []
section = np.zeros(frameSize, dtype=np.int16)
currentSamples = 0
while (1):
if (cap.grab()):
frame = []
frame = np.asarray(frame)
frame = cap.retrieve(frame, audioBaseIndex)
for i in range(len(frame[1][0])):
buffer.append(frame[1][0][i])
buffer_size = len(buffer)
if (buffer_size >= step):
section = list(section)
currentSamples += step
del section[0:step]
section.extend(buffer[0:step])
del buffer[0:step]
section = np.asarray(section)
if currentSamples < frameSize:
xmin = 0
xmax = (currentSamples) / samplingRate
else:
xmin = (currentSamples - frameSize) / samplingRate + 1
xmax = (currentSamples) / samplingRate
if self.graph == "ampl":
imgAmplitude = self.drawAmplitude(section)
imgAmplitude = self.drawAmplitudeScale(imgAmplitude, section, samplingRate, xmin, xmax)
cv.imshow("Display amplitude graph", imgAmplitude)
cv.waitKey(self.waitTime)
elif self.graph == "spec":
stft = self.STFT(section)
imgSpec = self.drawSpectrogram(stft)
imgSpec = self.drawSpectrogramColorbar(imgSpec, section, samplingRate, stft, xmin, xmax)
cv.imshow("Display spectrogram", imgSpec)
cv.waitKey(self.waitTime)
elif self.graph == "ampl_and_spec":
imgAmplitude = self.drawAmplitude(section)
stft = self.STFT(section)
imgSpec = self.drawSpectrogram(stft)
imgAmplitude = self.drawAmplitudeScale(imgAmplitude, section, samplingRate, xmin, xmax)
imgSpec = self.drawSpectrogramColorbar(imgSpec, section, samplingRate, stft, xmin, xmax)
imgTotal = self.concatenateImages(imgAmplitude, imgSpec)
cv.imshow("Display amplitude graph and spectrogram", imgTotal)
cv.waitKey(self.waitTime)
else:
break
def dynamicMicrophone(self):
cap = cv.VideoCapture()
params = [cv.CAP_PROP_AUDIO_STREAM, 0, cv.CAP_PROP_VIDEO_STREAM, -1]
params = np.asarray(params)
cap.open(0, cv.CAP_ANY, params)
if cap.isOpened() == False:
print("ERROR! Can't to open file")
return
audioBaseIndex = int(cap.get(cv.CAP_PROP_AUDIO_BASE_INDEX))
numberOfChannels = int(cap.get(cv.CAP_PROP_AUDIO_TOTAL_CHANNELS))
print("CAP_PROP_AUDIO_DATA_DEPTH: ", str((int(cap.get(cv.CAP_PROP_AUDIO_DATA_DEPTH)))))
print("CAP_PROP_AUDIO_SAMPLES_PER_SECOND: ", cap.get(cv.CAP_PROP_AUDIO_SAMPLES_PER_SECOND))
print("CAP_PROP_AUDIO_TOTAL_CHANNELS: ", numberOfChannels)
print("CAP_PROP_AUDIO_TOTAL_STREAMS: ", cap.get(cv.CAP_PROP_AUDIO_TOTAL_STREAMS))
frame = []
frame = np.asarray(frame)
samplingRate = int(cap.get(cv.CAP_PROP_AUDIO_SAMPLES_PER_SECOND))
step = int(self.updateTime * samplingRate)
frameSize = int(self.frameSizeTime * samplingRate)
self.xmarkup = self.frameSizeTime
currentSamples = 0
buffer = []
section = np.zeros(frameSize, dtype=np.int16)
cvTickFreq = cv.getTickFrequency()
sysTimeCurr = cv.getTickCount()
sysTimePrev = sysTimeCurr
self.waitTime = self.updateTime * 1000
while ((sysTimeCurr - sysTimePrev) / cvTickFreq < self.microTime):
if (cap.grab()):
frame = []
frame = np.asarray(frame)
frame = cap.retrieve(frame, audioBaseIndex)
for i in range(len(frame[1][0])):
buffer.append(frame[1][0][i])
sysTimeCurr = cv.getTickCount()
buffer_size = len(buffer)
if (buffer_size >= step):
section = list(section)
currentSamples += step
del section[0:step]
section.extend(buffer[0:step])
del buffer[0:step]
section = np.asarray(section)
if currentSamples < frameSize:
xmin = 0
xmax = (currentSamples) / samplingRate
else:
xmin = (currentSamples - frameSize) / samplingRate + 1
xmax = (currentSamples) / samplingRate
if self.graph == "ampl":
imgAmplitude = self.drawAmplitude(section)
imgAmplitude = self.drawAmplitudeScale(imgAmplitude, section, samplingRate, xmin, xmax)
cv.imshow("Display amplitude graph", imgAmplitude)
cv.waitKey(self.waitTime)
elif self.graph == "spec":
stft = self.STFT(section)
imgSpec = self.drawSpectrogram(stft)
imgSpec = self.drawSpectrogramColorbar(imgSpec, section, samplingRate, stft, xmin, xmax)
cv.imshow("Display spectrogram", imgSpec)
cv.waitKey(self.waitTime)
elif self.graph == "ampl_and_spec":
imgAmplitude = self.drawAmplitude(section)
stft = self.STFT(section)
imgSpec = self.drawSpectrogram(stft)
imgAmplitude = self.drawAmplitudeScale(imgAmplitude, section, samplingRate, xmin, xmax)
imgSpec = self.drawSpectrogramColorbar(imgSpec, section, samplingRate, stft, xmin, xmax)
imgTotal = self.concatenateImages(imgAmplitude, imgSpec)
cv.imshow("Display amplitude graph and spectrogram", imgTotal)
cv.waitKey(self.waitTime)
else:
break
def initAndCheckArgs(self, args):
if args.inputType != "file" and args.inputType != "microphone":
print("Error: ", args.inputType, " input method doesnt exist")
return False
if args.draw != "static" and args.draw != "dynamic":
print("Error: ", args.draw, " draw type doesnt exist")
return False
if args.graph != "ampl" and args.graph != "spec" and args.graph != "ampl_and_spec":
print("Error: ", args.graph, " type of graph doesnt exist")
return False
if args.windowType != "Rect" and args.windowType != "Hann" and args.windowType != "Hamming":
print("Error: ", args.windowType, " type of window doesnt exist")
return False
if args.windLen <= 0:
print("Error: windLen = ", args.windLen, " - incorrect value. Must be > 0")
return False
if args.overlap <= 0:
print("Error: overlap = ", args.overlap, " - incorrect value. Must be > 0")
return False
if args.rows <= 0:
print("Error: rows = ", args.rows, " - incorrect value. Must be > 0")
return False
if args.cols <= 0:
print("Error: cols = ", args.cols, " - incorrect value. Must be > 0")
return False
if args.xmarkup < 2:
print("Error: xmarkup = ", args.xmarkup, " - incorrect value. Must be >= 2")
return False
if args.ymarkup < 2:
print("Error: ymarkup = ", args.ymarkup, " - incorrect value. Must be >= 2")
return False
if args.zmarkup < 2:
print("Error: zmarkup = ", args.zmarkup, " - incorrect value. Must be >= 2")
return False
if args.microTime <= 0:
print("Error: microTime = ", args.microTime, " - incorrect value. Must be > 0")
return False
if args.frameSizeTime <= 0:
print("Error: frameSizeTime = ", args.frameSizeTime, " - incorrect value. Must be > 0")
return False
if args.updateTime <= 0:
print("Error: updateTime = ", args.updateTime, " - incorrect value. Must be > 0")
return False
if args.waitTime < 0:
print("Error: waitTime = ", args.waitTime, " - incorrect value. Must be >= 0")
return False
return True
if __name__ == "__main__":
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
description='''this sample draws a volume graph and/or spectrogram of audio/video files and microphone\nDefault usage: ./Spectrogram.exe''')
parser.add_argument("-i", "--inputType", dest="inputType", type=str, default="file", help="file or microphone")
parser.add_argument("-d", "--draw", dest="draw", type=str, default="static",
help="type of drawing: static - for plotting graph(s) across the entire input audio; dynamic - for plotting graph(s) in a time-updating window")
parser.add_argument("-g", "--graph", dest="graph", type=str, default="ampl_and_spec",
help="type of graph: amplitude graph or/and spectrogram. Please use tags below : ampl - draw the amplitude graph; spec - draw the spectrogram; ampl_and_spec - draw the amplitude graph and spectrogram on one image under each other")
parser.add_argument("-a", "--audio", dest="audio", type=str, default='Megamind.avi',
help="name and path to file")
parser.add_argument("-s", "--audioStream", dest="audioStream", type=int, default=1,
help=" CAP_PROP_AUDIO_STREAM value")
parser.add_argument("-t", '--windowType', dest="windowType", type=str, default="Rect",
help="type of window for STFT. Please use tags below : Rect/Hann/Hamming")
parser.add_argument("-l", '--windLen', dest="windLen", type=int, default=256, help="size of window for STFT")
parser.add_argument("-o", '--overlap', dest="overlap", type=int, default=128, help="overlap of windows for STFT")
parser.add_argument("-gd", '--grid', dest="enableGrid", type=bool, default=False, help="grid on amplitude graph(on/off)")
parser.add_argument("-r", '--rows', dest="rows", type=int, default=400, help="rows of output image")
parser.add_argument("-c", '--cols', dest="cols", type=int, default=900, help="cols of output image")
parser.add_argument("-x", '--xmarkup', dest="xmarkup", type=int, default=5,
help="number of x axis divisions (time asix)")
parser.add_argument("-y", '--ymarkup', dest="ymarkup", type=int, default=5,
help="number of y axis divisions (frequency or/and amplitude axis)") # ?
parser.add_argument("-z", '--zmarkup', dest="zmarkup", type=int, default=5,
help="number of z axis divisions (colorbar)") # ?
parser.add_argument("-m", '--microTime', dest="microTime", type=int, default=20,
help="time of recording audio with microphone in seconds")
parser.add_argument("-f", '--frameSizeTime', dest="frameSizeTime", type=int, default=5,
help="size of sliding window in seconds")
parser.add_argument("-u", '--updateTime', dest="updateTime", type=int, default=1,
help="update time of sliding window in seconds")
parser.add_argument("-w", '--waitTime', dest="waitTime", type=int, default=10,
help="parameter to cv.waitKey() for dynamic update, takes values in milliseconds")
args = parser.parse_args()
AudioDrawing(args).Draw()
@@ -0,0 +1,68 @@
'''
Showcases the use of background subtraction from a live video feed,
aswell as pass through of a known foreground parameter
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
def main():
cap = cv.VideoCapture(0)
if not cap.isOpened:
print("Capture source avaialable.")
exit()
# Create background subtractor
mog2_bg_subtractor = cv.createBackgroundSubtractorMOG2(history=300, varThreshold=50, detectShadows=False)
knn_bg_subtractor = cv.createBackgroundSubtractorKNN(history=300, detectShadows=False)
frame_count = 0
# Allows for a frame buffer for the mask to learn pre known foreground
show_count = 10
while True:
ret, frame = cap.read()
if not ret:
break
x = 100 + (frame_count % 10) * 3
frame = cv.resize(frame, (640, 480))
aKnownForegroundMask = np.zeros(frame.shape[:2], dtype=np.uint8)
# Allow for models to "settle"/learn
if frame_count > show_count:
cv.rectangle(aKnownForegroundMask, (x,200), (x+50,300), 255, -1)
cv.rectangle(aKnownForegroundMask, (540,180), (640,480), 255, -1)
#MOG2 Subtraction
mog2_with_mask = mog2_bg_subtractor.apply(frame,knownForegroundMask=aKnownForegroundMask)
mog2_without_mask = mog2_bg_subtractor.apply(frame)
#KNN Subtraction
knn_with_mask = knn_bg_subtractor.apply(frame,knownForegroundMask=aKnownForegroundMask)
knn_without_mask = knn_bg_subtractor.apply(frame)
# Display the 3 parameter apply and the 4 parameter apply for both subtractors
cv.imshow("MOG2 With a Foreground Mask", mog2_with_mask)
cv.imshow("MOG2 Without a Foreground Mask", mog2_without_mask)
cv.imshow("KNN With a Foreground Mask", knn_with_mask)
cv.imshow("KNN Without a Foreground Mask", knn_without_mask)
key = cv.waitKey(30)
if key == 27: # ESC
break
frame_count += 1
cap.release()
cv.destroyAllWindows()
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+67
View File
@@ -0,0 +1,67 @@
#!/usr/bin/env python
'''
browse.py
=========
Sample shows how to implement a simple hi resolution image navigation
Usage
-----
browse.py [image filename]
'''
# Python 2/3 compatibility
from __future__ import print_function
import sys
PY3 = sys.version_info[0] == 3
if PY3:
xrange = range
import numpy as np
import cv2 as cv
# built-in modules
import sys
def main():
if len(sys.argv) > 1:
fn = cv.samples.findFile(sys.argv[1])
print('loading %s ...' % fn)
img = cv.imread(fn)
if img is None:
print('Failed to load fn:', fn)
sys.exit(1)
else:
sz = 4096
print('generating %dx%d procedural image ...' % (sz, sz))
img = np.zeros((sz, sz), np.uint8)
track = np.cumsum(np.random.rand(500000, 2)-0.5, axis=0)
track = np.int32(track*10 + (sz/2, sz/2))
cv.polylines(img, [track], 0, 255, 1, cv.LINE_AA)
small = img
for _i in xrange(3):
small = cv.pyrDown(small)
def onmouse(event, x, y, flags, param):
h, _w = img.shape[:2]
h1, _w1 = small.shape[:2]
x, y = 1.0*x*h/h1, 1.0*y*h/h1
zoom = cv.getRectSubPix(img, (800, 600), (x+0.5, y+0.5))
cv.imshow('zoom', zoom)
cv.imshow('preview', small)
cv.setMouseCallback('preview', onmouse)
cv.waitKey()
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+209
View File
@@ -0,0 +1,209 @@
#!/usr/bin/env python
'''
camera calibration for distorted images with chess board samples
reads distorted images, calculates the calibration and write undistorted images
usage:
calibrate.py [--debug <output path>] [-w <width>] [-h <height>] [-t <pattern type>] [--square_size=<square size>]
[--marker_size=<aruco marker size>] [--aruco_dict=<aruco dictionary name>] [<image mask>]
usage example:
calibrate.py -w 4 -h 6 -t chessboard --square_size=50 ../data/left*.jpg
default values:
--debug: ./output/
-w: 4
-h: 6
-t: chessboard
--square_size: 10
--marker_size: 5
--aruco_dict: DICT_4X4_50
--threads: 4
<image mask> defaults to ../data/left*.jpg
NOTE: Chessboard size is defined in inner corners. Charuco board size is defined in units.
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
# local modules
from common import splitfn
# built-in modules
import os
def main():
import sys
import getopt
from glob import glob
args, img_names = getopt.getopt(sys.argv[1:], 'w:h:t:', ['debug=','square_size=', 'marker_size=',
'aruco_dict=', 'threads=', ])
args = dict(args)
args.setdefault('--debug', './output/')
args.setdefault('-w', 4)
args.setdefault('-h', 6)
args.setdefault('-t', 'chessboard')
args.setdefault('--square_size', 10)
args.setdefault('--marker_size', 5)
args.setdefault('--aruco_dict', 'DICT_4X4_50')
args.setdefault('--threads', 4)
if not img_names:
img_mask = '../data/left??.jpg' # default
img_names = glob(img_mask)
debug_dir = args.get('--debug')
if debug_dir and not os.path.isdir(debug_dir):
os.mkdir(debug_dir)
height = int(args.get('-h'))
width = int(args.get('-w'))
pattern_type = str(args.get('-t'))
square_size = float(args.get('--square_size'))
marker_size = float(args.get('--marker_size'))
aruco_dict_name = str(args.get('--aruco_dict'))
pattern_size = (width, height)
if pattern_type == 'chessboard':
pattern_points = np.zeros((np.prod(pattern_size), 3), np.float32)
pattern_points[:, :2] = np.indices(pattern_size).T.reshape(-1, 2)
pattern_points *= square_size
obj_points = []
img_points = []
h, w = cv.imread(img_names[0], cv.IMREAD_GRAYSCALE).shape[:2] # TODO: use imquery call to retrieve results
aruco_dicts = {
'DICT_4X4_50': cv.aruco.DICT_4X4_50,
'DICT_4X4_100': cv.aruco.DICT_4X4_100,
'DICT_4X4_250': cv.aruco.DICT_4X4_250,
'DICT_4X4_1000': cv.aruco.DICT_4X4_1000,
'DICT_5X5_50': cv.aruco.DICT_5X5_50,
'DICT_5X5_100': cv.aruco.DICT_5X5_100,
'DICT_5X5_250': cv.aruco.DICT_5X5_250,
'DICT_5X5_1000': cv.aruco.DICT_5X5_1000,
'DICT_6X6_50': cv.aruco.DICT_6X6_50,
'DICT_6X6_100': cv.aruco.DICT_6X6_100,
'DICT_6X6_250': cv.aruco.DICT_6X6_250,
'DICT_6X6_1000': cv.aruco.DICT_6X6_1000,
'DICT_7X7_50': cv.aruco.DICT_7X7_50,
'DICT_7X7_100': cv.aruco.DICT_7X7_100,
'DICT_7X7_250': cv.aruco.DICT_7X7_250,
'DICT_7X7_1000': cv.aruco.DICT_7X7_1000,
'DICT_ARUCO_ORIGINAL': cv.aruco.DICT_ARUCO_ORIGINAL,
'DICT_APRILTAG_16h5': cv.aruco.DICT_APRILTAG_16h5,
'DICT_APRILTAG_25h9': cv.aruco.DICT_APRILTAG_25h9,
'DICT_APRILTAG_36h10': cv.aruco.DICT_APRILTAG_36h10,
'DICT_APRILTAG_36h11': cv.aruco.DICT_APRILTAG_36h11,
'DICT_ARUCO_MIP_36h12': cv.aruco.DICT_ARUCO_MIP_36h12
}
if (aruco_dict_name not in set(aruco_dicts.keys())):
print("unknown aruco dictionary name")
return None
aruco_dict = cv.aruco.getPredefinedDictionary(aruco_dicts[aruco_dict_name])
board = cv.aruco.CharucoBoard(pattern_size, square_size, marker_size, aruco_dict)
charuco_detector = cv.aruco.CharucoDetector(board)
def processImage(fn):
print('processing %s... ' % fn)
img = cv.imread(fn, cv.IMREAD_GRAYSCALE)
if img is None:
print("Failed to load", fn)
return None
assert w == img.shape[1] and h == img.shape[0], ("size: %d x %d ... " % (img.shape[1], img.shape[0]))
found = False
corners = 0
if pattern_type == 'chessboard':
found, corners = cv.findChessboardCorners(img, pattern_size)
if found:
term = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_COUNT, 30, 0.1)
cv.cornerSubPix(img, corners, (5, 5), (-1, -1), term)
frame_img_points = corners.reshape(-1, 2)
frame_obj_points = pattern_points
elif pattern_type == 'charucoboard':
corners, charucoIds, _, _ = charuco_detector.detectBoard(img)
if (len(corners) > 0):
frame_obj_points, frame_img_points = board.matchImagePoints(corners, charucoIds)
found = True
else:
found = False
else:
print("unknown pattern type", pattern_type)
return None
if debug_dir:
vis = cv.cvtColor(img, cv.COLOR_GRAY2BGR)
if pattern_type == 'chessboard':
cv.drawChessboardCorners(vis, pattern_size, corners, found)
elif pattern_type == 'charucoboard':
cv.aruco.drawDetectedCornersCharuco(vis, corners, charucoIds=charucoIds)
_path, name, _ext = splitfn(fn)
outfile = os.path.join(debug_dir, name + '_board.png')
cv.imwrite(outfile, vis)
if not found:
print('pattern not found')
return None
print(' %s... OK' % fn)
return (frame_img_points, frame_obj_points)
threads_num = int(args.get('--threads'))
if threads_num <= 1:
chessboards = [processImage(fn) for fn in img_names]
else:
print("Run with %d threads..." % threads_num)
from multiprocessing.dummy import Pool as ThreadPool
pool = ThreadPool(threads_num)
chessboards = pool.map(processImage, img_names)
chessboards = [x for x in chessboards if x is not None]
for (corners, pattern_points) in chessboards:
img_points.append(corners)
obj_points.append(pattern_points)
# calculate camera distortion
rms, camera_matrix, dist_coefs, _rvecs, _tvecs = cv.calibrateCamera(obj_points, img_points, (w, h), None, None)
print("\nRMS:", rms)
print("camera matrix:\n", camera_matrix)
print("distortion coefficients: ", dist_coefs.ravel())
# undistort the image with the calibration
print('')
for fn in img_names if debug_dir else []:
_path, name, _ext = splitfn(fn)
img_found = os.path.join(debug_dir, name + '_board.png')
outfile = os.path.join(debug_dir, name + '_undistorted.png')
img = cv.imread(img_found)
if img is None:
continue
h, w = img.shape[:2]
newcameramtx, roi = cv.getOptimalNewCameraMatrix(camera_matrix, dist_coefs, (w, h), 1, (w, h))
dst = cv.undistort(img, camera_matrix, dist_coefs, None, newcameramtx)
# crop and save the image
x, y, w, h = roi
dst = dst[y:y+h, x:x+w]
print('Undistorted image written to: %s' % outfile)
cv.imwrite(outfile, dst)
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+240
View File
@@ -0,0 +1,240 @@
#!/usr/bin/env python
'''
Plot camera calibration extrinsics.
usage:
camera_calibration_show_extrinsics.py [--calibration <input path>] [--cam_width] [--cam_height] [--scale_focal] [--patternCentric ]
default values:
--calibration : left_intrinsics.yml
--cam_width : 0.064/2
--cam_height : 0.048/2
--scale_focal : 40
--patternCentric : True
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
from numpy import linspace
def inverse_homogeneoux_matrix(M):
R = M[0:3, 0:3]
T = M[0:3, 3]
M_inv = np.identity(4)
M_inv[0:3, 0:3] = R.T
M_inv[0:3, 3] = -(R.T).dot(T)
return M_inv
def transform_to_matplotlib_frame(cMo, X, inverse=False):
M = np.identity(4)
M[1,1] = 0
M[1,2] = 1
M[2,1] = -1
M[2,2] = 0
if inverse:
return M.dot(inverse_homogeneoux_matrix(cMo).dot(X))
else:
return M.dot(cMo.dot(X))
def create_camera_model(camera_matrix, width, height, scale_focal, draw_frame_axis=False):
fx = camera_matrix[0,0]
fy = camera_matrix[1,1]
focal = 2 / (fx + fy)
f_scale = scale_focal * focal
# draw image plane
X_img_plane = np.ones((4,5))
X_img_plane[0:3,0] = [-width, height, f_scale]
X_img_plane[0:3,1] = [width, height, f_scale]
X_img_plane[0:3,2] = [width, -height, f_scale]
X_img_plane[0:3,3] = [-width, -height, f_scale]
X_img_plane[0:3,4] = [-width, height, f_scale]
# draw triangle above the image plane
X_triangle = np.ones((4,3))
X_triangle[0:3,0] = [-width, -height, f_scale]
X_triangle[0:3,1] = [0, -2*height, f_scale]
X_triangle[0:3,2] = [width, -height, f_scale]
# draw camera
X_center1 = np.ones((4,2))
X_center1[0:3,0] = [0, 0, 0]
X_center1[0:3,1] = [-width, height, f_scale]
X_center2 = np.ones((4,2))
X_center2[0:3,0] = [0, 0, 0]
X_center2[0:3,1] = [width, height, f_scale]
X_center3 = np.ones((4,2))
X_center3[0:3,0] = [0, 0, 0]
X_center3[0:3,1] = [width, -height, f_scale]
X_center4 = np.ones((4,2))
X_center4[0:3,0] = [0, 0, 0]
X_center4[0:3,1] = [-width, -height, f_scale]
# draw camera frame axis
X_frame1 = np.ones((4,2))
X_frame1[0:3,0] = [0, 0, 0]
X_frame1[0:3,1] = [f_scale/2, 0, 0]
X_frame2 = np.ones((4,2))
X_frame2[0:3,0] = [0, 0, 0]
X_frame2[0:3,1] = [0, f_scale/2, 0]
X_frame3 = np.ones((4,2))
X_frame3[0:3,0] = [0, 0, 0]
X_frame3[0:3,1] = [0, 0, f_scale/2]
if draw_frame_axis:
return [X_img_plane, X_triangle, X_center1, X_center2, X_center3, X_center4, X_frame1, X_frame2, X_frame3]
else:
return [X_img_plane, X_triangle, X_center1, X_center2, X_center3, X_center4]
def create_board_model(extrinsics, board_width, board_height, square_size, draw_frame_axis=False):
width = board_width*square_size
height = board_height*square_size
# draw calibration board
X_board = np.ones((4,5))
#X_board_cam = np.ones((extrinsics.shape[0],4,5))
X_board[0:3,0] = [0,0,0]
X_board[0:3,1] = [width,0,0]
X_board[0:3,2] = [width,height,0]
X_board[0:3,3] = [0,height,0]
X_board[0:3,4] = [0,0,0]
# draw board frame axis
X_frame1 = np.ones((4,2))
X_frame1[0:3,0] = [0, 0, 0]
X_frame1[0:3,1] = [height/2, 0, 0]
X_frame2 = np.ones((4,2))
X_frame2[0:3,0] = [0, 0, 0]
X_frame2[0:3,1] = [0, height/2, 0]
X_frame3 = np.ones((4,2))
X_frame3[0:3,0] = [0, 0, 0]
X_frame3[0:3,1] = [0, 0, height/2]
if draw_frame_axis:
return [X_board, X_frame1, X_frame2, X_frame3]
else:
return [X_board]
def draw_camera_boards(ax, camera_matrix, cam_width, cam_height, scale_focal,
extrinsics, board_width, board_height, square_size,
patternCentric):
from matplotlib import cm
min_values = np.zeros((3,1))
min_values = np.inf
max_values = np.zeros((3,1))
max_values = -np.inf
if patternCentric:
X_moving = create_camera_model(camera_matrix, cam_width, cam_height, scale_focal)
X_static = create_board_model(extrinsics, board_width, board_height, square_size)
else:
X_static = create_camera_model(camera_matrix, cam_width, cam_height, scale_focal, True)
X_moving = create_board_model(extrinsics, board_width, board_height, square_size)
cm_subsection = linspace(0.0, 1.0, extrinsics.shape[0])
colors = [ cm.jet(x) for x in cm_subsection ]
for i in range(len(X_static)):
X = np.zeros(X_static[i].shape)
for j in range(X_static[i].shape[1]):
X[:,j] = transform_to_matplotlib_frame(np.eye(4), X_static[i][:,j])
ax.plot3D(X[0,:], X[1,:], X[2,:], color='r')
min_values = np.minimum(min_values, X[0:3,:].min(1))
max_values = np.maximum(max_values, X[0:3,:].max(1))
for idx in range(extrinsics.shape[0]):
R, _ = cv.Rodrigues(extrinsics[idx,0:3])
cMo = np.eye(4,4)
cMo[0:3,0:3] = R
cMo[0:3,3] = extrinsics[idx,3:6]
for i in range(len(X_moving)):
X = np.zeros(X_moving[i].shape)
for j in range(X_moving[i].shape[1]):
X[0:4,j] = transform_to_matplotlib_frame(cMo, X_moving[i][0:4,j], patternCentric)
ax.plot3D(X[0,:], X[1,:], X[2,:], color=colors[idx])
min_values = np.minimum(min_values, X[0:3,:].min(1))
max_values = np.maximum(max_values, X[0:3,:].max(1))
return min_values, max_values
def main():
import argparse
parser = argparse.ArgumentParser(description='Plot camera calibration extrinsics.',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('--calibration', type=str, default='left_intrinsics.yml',
help='YAML camera calibration file.')
parser.add_argument('--cam_width', type=float, default=0.064/2,
help='Width/2 of the displayed camera.')
parser.add_argument('--cam_height', type=float, default=0.048/2,
help='Height/2 of the displayed camera.')
parser.add_argument('--scale_focal', type=float, default=40,
help='Value to scale the focal length.')
parser.add_argument('--patternCentric', action='store_true',
help='The calibration board is static and the camera is moving.')
args = parser.parse_args()
fs = cv.FileStorage(cv.samples.findFile(args.calibration), cv.FILE_STORAGE_READ)
board_width = int(fs.getNode('board_width').real())
board_height = int(fs.getNode('board_height').real())
square_size = fs.getNode('square_size').real()
camera_matrix = fs.getNode('camera_matrix').mat()
extrinsics = fs.getNode('extrinsic_parameters').mat()
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D # pylint: disable=unused-variable
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_aspect("auto")
cam_width = args.cam_width
cam_height = args.cam_height
scale_focal = args.scale_focal
min_values, max_values = draw_camera_boards(ax, camera_matrix, cam_width, cam_height,
scale_focal, extrinsics, board_width,
board_height, square_size, args.patternCentric)
X_min = min_values[0]
X_max = max_values[0]
Y_min = min_values[1]
Y_max = max_values[1]
Z_min = min_values[2]
Z_max = max_values[2]
max_range = np.array([X_max-X_min, Y_max-Y_min, Z_max-Z_min]).max() / 2.0
mid_x = (X_max+X_min) * 0.5
mid_y = (Y_max+Y_min) * 0.5
mid_z = (Z_max+Z_min) * 0.5
ax.set_xlim(mid_x - max_range, mid_x + max_range)
ax.set_ylim(mid_y - max_range, mid_y + max_range)
ax.set_zlim(mid_z - max_range, mid_z + max_range)
ax.set_xlabel('x')
ax.set_ylabel('z')
ax.set_zlabel('-y')
ax.set_title('Extrinsic Parameters Visualization')
plt.show()
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+128
View File
@@ -0,0 +1,128 @@
#!/usr/bin/env python
'''
Camshift tracker
================
This is a demo that shows mean-shift based tracking
You select a color objects such as your face and it tracks it.
This reads from video camera (0 by default, or the camera number the user enters)
[1] http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.14.7673
Usage:
------
camshift.py [<video source>]
To initialize tracking, select the object with mouse
Keys:
-----
ESC - exit
b - toggle back-projected probability visualization
'''
# Python 2/3 compatibility
from __future__ import print_function
import sys
PY3 = sys.version_info[0] == 3
if PY3:
xrange = range
import numpy as np
import cv2 as cv
# local module
import video
from video import presets
class App(object):
def __init__(self, video_src):
self.cam = video.create_capture(video_src, presets['cube'])
_ret, self.frame = self.cam.read()
cv.namedWindow('camshift')
cv.setMouseCallback('camshift', self.onmouse)
self.selection = None
self.drag_start = None
self.show_backproj = False
self.track_window = None
def onmouse(self, event, x, y, flags, param):
if event == cv.EVENT_LBUTTONDOWN:
self.drag_start = (x, y)
self.track_window = None
if self.drag_start:
xmin = min(x, self.drag_start[0])
ymin = min(y, self.drag_start[1])
xmax = max(x, self.drag_start[0])
ymax = max(y, self.drag_start[1])
self.selection = (xmin, ymin, xmax, ymax)
if event == cv.EVENT_LBUTTONUP:
self.drag_start = None
self.track_window = (xmin, ymin, xmax - xmin, ymax - ymin)
def show_hist(self):
bin_count = self.hist.shape[0]
bin_w = 24
img = np.zeros((256, bin_count*bin_w, 3), np.uint8)
for i in xrange(bin_count):
h = int(self.hist[i])
cv.rectangle(img, (i*bin_w+2, 255), ((i+1)*bin_w-2, 255-h), (int(180.0*i/bin_count), 255, 255), -1)
img = cv.cvtColor(img, cv.COLOR_HSV2BGR)
cv.imshow('hist', img)
def run(self):
while True:
_ret, self.frame = self.cam.read()
vis = self.frame.copy()
hsv = cv.cvtColor(self.frame, cv.COLOR_BGR2HSV)
mask = cv.inRange(hsv, np.array((0., 60., 32.)), np.array((180., 255., 255.)))
if self.selection:
x0, y0, x1, y1 = self.selection
hsv_roi = hsv[y0:y1, x0:x1]
mask_roi = mask[y0:y1, x0:x1]
hist = cv.calcHist( [hsv_roi], [0], mask_roi, [16], [0, 180] )
cv.normalize(hist, hist, 0, 255, cv.NORM_MINMAX)
self.hist = hist.reshape(-1)
self.show_hist()
vis_roi = vis[y0:y1, x0:x1]
cv.bitwise_not(vis_roi, vis_roi)
vis[mask == 0] = 0
if self.track_window and self.track_window[2] > 0 and self.track_window[3] > 0:
self.selection = None
prob = cv.calcBackProject([hsv], [0], self.hist, [0, 180], 1)
prob &= mask
term_crit = ( cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 1 )
track_box, self.track_window = cv.CamShift(prob, self.track_window, term_crit)
if self.show_backproj:
vis[:] = prob[...,np.newaxis]
try:
cv.ellipse(vis, track_box, (0, 0, 255), 2)
except:
print(track_box)
cv.imshow('camshift', vis)
ch = cv.waitKey(5)
if ch == 27:
break
if ch == ord('b'):
self.show_backproj = not self.show_backproj
cv.destroyAllWindows()
if __name__ == '__main__':
print(__doc__)
import sys
try:
video_src = sys.argv[1]
except:
video_src = 0
App(video_src).run()
+92
View File
@@ -0,0 +1,92 @@
#!/usr/bin/env python
'''
Coherence-enhancing filtering example
=====================================
inspired by
Joachim Weickert "Coherence-Enhancing Shock Filters"
http://www.mia.uni-saarland.de/Publications/weickert-dagm03.pdf
'''
# Python 2/3 compatibility
from __future__ import print_function
import sys
PY3 = sys.version_info[0] == 3
if PY3:
xrange = range
import numpy as np
import cv2 as cv
def coherence_filter(img, sigma = 11, str_sigma = 11, blend = 0.5, iter_n = 4):
h, w = img.shape[:2]
for i in xrange(iter_n):
print(i)
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
eigen = cv.cornerEigenValsAndVecs(gray, str_sigma, 3)
eigen = eigen.reshape(h, w, 3, 2) # [[e1, e2], v1, v2]
x, y = eigen[:,:,1,0], eigen[:,:,1,1]
gxx = cv.Sobel(gray, cv.CV_32F, 2, 0, ksize=sigma)
gxy = cv.Sobel(gray, cv.CV_32F, 1, 1, ksize=sigma)
gyy = cv.Sobel(gray, cv.CV_32F, 0, 2, ksize=sigma)
gvv = x*x*gxx + 2*x*y*gxy + y*y*gyy
m = gvv < 0
ero = cv.erode(img, None)
dil = cv.dilate(img, None)
img1 = ero
img1[m] = dil[m]
img = np.uint8(img*(1.0 - blend) + img1*blend)
print('done')
return img
def main():
import sys
try:
fn = sys.argv[1]
except:
fn = 'baboon.jpg'
src = cv.imread(cv.samples.findFile(fn))
def nothing(*argv):
pass
def update():
sigma = cv.getTrackbarPos('sigma', 'control')*2+1
str_sigma = cv.getTrackbarPos('str_sigma', 'control')*2+1
blend = cv.getTrackbarPos('blend', 'control') / 10.0
print('sigma: %d str_sigma: %d blend_coef: %f' % (sigma, str_sigma, blend))
dst = coherence_filter(src, sigma=sigma, str_sigma = str_sigma, blend = blend)
cv.imshow('dst', dst)
cv.namedWindow('control', 0)
cv.createTrackbar('sigma', 'control', 9, 15, nothing)
cv.createTrackbar('blend', 'control', 7, 10, nothing)
cv.createTrackbar('str_sigma', 'control', 9, 15, nothing)
print('Press SPACE to update the image\n')
cv.imshow('src', src)
update()
while True:
ch = cv.waitKey()
if ch == ord(' '):
update()
if ch == 27:
break
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+73
View File
@@ -0,0 +1,73 @@
#!/usr/bin/env python
'''
Video histogram sample to show live histogram of video
Keys:
ESC - exit
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
# built-in modules
import sys
# local modules
import video
class App():
def set_scale(self, val):
self.hist_scale = val
def run(self):
hsv_map = np.zeros((180, 256, 3), np.uint8)
h, s = np.indices(hsv_map.shape[:2])
hsv_map[:,:,0] = h
hsv_map[:,:,1] = s
hsv_map[:,:,2] = 255
hsv_map = cv.cvtColor(hsv_map, cv.COLOR_HSV2BGR)
cv.imshow('hsv_map', hsv_map)
cv.namedWindow('hist', 0)
self.hist_scale = 10
cv.createTrackbar('scale', 'hist', self.hist_scale, 32, self.set_scale)
try:
fn = sys.argv[1]
except:
fn = 0
cam = video.create_capture(fn, fallback='synth:bg=baboon.jpg:class=chess:noise=0.05')
while True:
_flag, frame = cam.read()
cv.imshow('camera', frame)
small = cv.pyrDown(frame)
hsv = cv.cvtColor(small, cv.COLOR_BGR2HSV)
dark = hsv[...,2] < 32
hsv[dark] = 0
h = cv.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
h = np.clip(h*0.005*self.hist_scale, 0, 1)
vis = hsv_map*h[:,:,np.newaxis] / 255.0
cv.imshow('hist', vis)
ch = cv.waitKey(1)
if ch == 27:
break
print('Done')
if __name__ == '__main__':
print(__doc__)
App().run()
cv.destroyAllWindows()
+237
View File
@@ -0,0 +1,237 @@
#!/usr/bin/env python
'''
This module contains some common routines used by other samples.
'''
# Python 2/3 compatibility
from __future__ import print_function
import sys
PY3 = sys.version_info[0] == 3
if PY3:
from functools import reduce
import numpy as np
import cv2 as cv
# built-in modules
import os
import itertools as it
from contextlib import contextmanager
image_extensions = ['.bmp', '.jpg', '.jpeg', '.png', '.tif', '.tiff', '.pbm', '.pgm', '.ppm']
class Bunch(object):
def __init__(self, **kw):
self.__dict__.update(kw)
def __str__(self):
return str(self.__dict__)
def splitfn(fn):
path, fn = os.path.split(fn)
name, ext = os.path.splitext(fn)
return path, name, ext
def anorm2(a):
return (a*a).sum(-1)
def anorm(a):
return np.sqrt( anorm2(a) )
def homotrans(H, x, y):
xs = H[0, 0]*x + H[0, 1]*y + H[0, 2]
ys = H[1, 0]*x + H[1, 1]*y + H[1, 2]
s = H[2, 0]*x + H[2, 1]*y + H[2, 2]
return xs/s, ys/s
def to_rect(a):
a = np.ravel(a)
if len(a) == 2:
a = (0, 0, a[0], a[1])
return np.array(a, np.float64).reshape(2, 2)
def rect2rect_mtx(src, dst):
src, dst = to_rect(src), to_rect(dst)
cx, cy = (dst[1] - dst[0]) / (src[1] - src[0])
tx, ty = dst[0] - src[0] * (cx, cy)
M = np.float64([[ cx, 0, tx],
[ 0, cy, ty],
[ 0, 0, 1]])
return M
def lookat(eye, target, up = (0, 0, 1)):
fwd = np.asarray(target, np.float64) - eye
fwd /= anorm(fwd)
right = np.cross(fwd, up)
right /= anorm(right)
down = np.cross(fwd, right)
R = np.float64([right, down, fwd])
tvec = -np.dot(R, eye)
return R, tvec
def mtx2rvec(R):
w, u, vt = cv.SVDecomp(R - np.eye(3))
p = vt[0] + u[:,0]*w[0] # same as np.dot(R, vt[0])
c = np.dot(vt[0], p)
s = np.dot(vt[1], p)
axis = np.cross(vt[0], vt[1])
return axis * np.arctan2(s, c)
def draw_str(dst, target, s):
x, y = target
cv.putText(dst, s, (x+1, y+1), cv.FONT_HERSHEY_PLAIN, 1.0, (0, 0, 0), thickness = 2, lineType=cv.LINE_AA)
cv.putText(dst, s, (x, y), cv.FONT_HERSHEY_PLAIN, 1.0, (255, 255, 255), lineType=cv.LINE_AA)
class Sketcher:
def __init__(self, windowname, dests, colors_func):
self.prev_pt = None
self.windowname = windowname
self.dests = dests
self.colors_func = colors_func
self.dirty = False
self.show()
cv.setMouseCallback(self.windowname, self.on_mouse)
def show(self):
cv.imshow(self.windowname, self.dests[0])
def on_mouse(self, event, x, y, flags, param):
pt = (x, y)
if event == cv.EVENT_LBUTTONDOWN:
self.prev_pt = pt
elif event == cv.EVENT_LBUTTONUP:
self.prev_pt = None
if self.prev_pt and flags & cv.EVENT_FLAG_LBUTTON:
for dst, color in zip(self.dests, self.colors_func()):
cv.line(dst, self.prev_pt, pt, color, 5)
self.dirty = True
self.prev_pt = pt
self.show()
# palette data from matplotlib/_cm.py
_jet_data = {'red': ((0., 0, 0), (0.35, 0, 0), (0.66, 1, 1), (0.89,1, 1),
(1, 0.5, 0.5)),
'green': ((0., 0, 0), (0.125,0, 0), (0.375,1, 1), (0.64,1, 1),
(0.91,0,0), (1, 0, 0)),
'blue': ((0., 0.5, 0.5), (0.11, 1, 1), (0.34, 1, 1), (0.65,0, 0),
(1, 0, 0))}
cmap_data = { 'jet' : _jet_data }
def make_cmap(name, n=256):
data = cmap_data[name]
xs = np.linspace(0.0, 1.0, n)
channels = []
eps = 1e-6
for ch_name in ['blue', 'green', 'red']:
ch_data = data[ch_name]
xp, yp = [], []
for x, y1, y2 in ch_data:
xp += [x, x+eps]
yp += [y1, y2]
ch = np.interp(xs, xp, yp)
channels.append(ch)
return np.uint8(np.array(channels).T*255)
def nothing(*arg, **kw):
pass
def clock():
return cv.getTickCount() / cv.getTickFrequency()
@contextmanager
def Timer(msg):
print(msg, '...',)
start = clock()
try:
yield
finally:
print("%.2f ms" % ((clock()-start)*1000))
class StatValue:
def __init__(self, smooth_coef = 0.5):
self.value = None
self.smooth_coef = smooth_coef
def update(self, v):
if self.value is None:
self.value = v
else:
c = self.smooth_coef
self.value = c * self.value + (1.0-c) * v
class RectSelector:
def __init__(self, win, callback):
self.win = win
self.callback = callback
cv.setMouseCallback(win, self.onmouse)
self.drag_start = None
self.drag_rect = None
def onmouse(self, event, x, y, flags, param):
x, y = np.int16([x, y]) # BUG
if event == cv.EVENT_LBUTTONDOWN:
self.drag_start = (x, y)
return
if self.drag_start:
if flags & cv.EVENT_FLAG_LBUTTON:
xo, yo = self.drag_start
x0, y0 = np.minimum([xo, yo], [x, y])
x1, y1 = np.maximum([xo, yo], [x, y])
self.drag_rect = None
if x1-x0 > 0 and y1-y0 > 0:
self.drag_rect = (x0, y0, x1, y1)
else:
rect = self.drag_rect
self.drag_start = None
self.drag_rect = None
if rect:
self.callback(rect)
def draw(self, vis):
if not self.drag_rect:
return False
x0, y0, x1, y1 = self.drag_rect
cv.rectangle(vis, (x0, y0), (x1, y1), (0, 255, 0), 2)
return True
@property
def dragging(self):
return self.drag_rect is not None
def grouper(n, iterable, fillvalue=None):
'''grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx'''
args = [iter(iterable)] * n
if PY3:
output = it.zip_longest(fillvalue=fillvalue, *args)
else:
output = it.izip_longest(fillvalue=fillvalue, *args)
return output
def mosaic(w, imgs):
'''Make a grid from images.
w -- number of grid columns
imgs -- images (must have same size and format)
'''
imgs = iter(imgs)
if PY3:
img0 = next(imgs)
else:
img0 = imgs.next()
pad = np.zeros_like(img0)
imgs = it.chain([img0], imgs)
rows = grouper(w, imgs, pad)
return np.vstack(list(map(np.hstack, rows)))
def getsize(img):
h, w = img.shape[:2]
return w, h
def mdot(*args):
return reduce(np.dot, args)
def draw_keypoints(vis, keypoints, color = (0, 255, 255)):
for kp in keypoints:
x, y = kp.pt
cv.circle(vis, (int(x), int(y)), 2, color)
+74
View File
@@ -0,0 +1,74 @@
#!/usr/bin/env python
'''
This program illustrates the use of findContours and drawContours.
The original image is put up along with the image of drawn contours.
Usage:
contours.py
A trackbar is put up which controls the contour level from -3 to 3
'''
# Python 2/3 compatibility
from __future__ import print_function
import sys
PY3 = sys.version_info[0] == 3
if PY3:
xrange = range
import numpy as np
import cv2 as cv
def make_image():
img = np.zeros((500, 500), np.uint8)
black, white = 0, 255
for i in xrange(6):
dx = int((i%2)*250 - 30)
dy = int((i/2.)*150)
if i == 0:
for j in xrange(11):
angle = (j+5)*np.pi/21
c, s = np.cos(angle), np.sin(angle)
x1, y1 = np.int32([dx+100+j*10-80*c, dy+100-90*s])
x2, y2 = np.int32([dx+100+j*10-30*c, dy+100-30*s])
cv.line(img, (x1, y1), (x2, y2), white)
cv.ellipse( img, (dx+150, dy+100), (100,70), 0, 0, 360, white, -1 )
cv.ellipse( img, (dx+115, dy+70), (30,20), 0, 0, 360, black, -1 )
cv.ellipse( img, (dx+185, dy+70), (30,20), 0, 0, 360, black, -1 )
cv.ellipse( img, (dx+115, dy+70), (15,15), 0, 0, 360, white, -1 )
cv.ellipse( img, (dx+185, dy+70), (15,15), 0, 0, 360, white, -1 )
cv.ellipse( img, (dx+115, dy+70), (5,5), 0, 0, 360, black, -1 )
cv.ellipse( img, (dx+185, dy+70), (5,5), 0, 0, 360, black, -1 )
cv.ellipse( img, (dx+150, dy+100), (10,5), 0, 0, 360, black, -1 )
cv.ellipse( img, (dx+150, dy+150), (40,10), 0, 0, 360, black, -1 )
cv.ellipse( img, (dx+27, dy+100), (20,35), 0, 0, 360, white, -1 )
cv.ellipse( img, (dx+273, dy+100), (20,35), 0, 0, 360, white, -1 )
return img
def main():
img = make_image()
h, w = img.shape[:2]
contours0, hierarchy = cv.findContours( img.copy(), cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
contours = [cv.approxPolyDP(cnt, 3, True) for cnt in contours0]
def update(levels):
vis = np.zeros((h, w, 3), np.uint8)
levels = levels - 3
cv.drawContours( vis, contours, (-1, 2)[levels <= 0], (128,255,255),
3, cv.LINE_AA, hierarchy, abs(levels) )
cv.imshow('contours', vis)
update(3)
cv.createTrackbar( "levels+3", "contours", 3, 7, update )
cv.imshow('image', img)
cv.waitKey()
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+137
View File
@@ -0,0 +1,137 @@
#!/usr/bin/env python
'''
Wiener deconvolution.
Sample shows how DFT can be used to perform Weiner deconvolution [1]
of an image with user-defined point spread function (PSF)
Usage:
deconvolution.py [--circle]
[--angle <degrees>]
[--d <diameter>]
[--snr <signal/noise ratio in db>]
[<input image>]
Use sliders to adjust PSF paramitiers.
Keys:
SPACE - switch btw linear/circular PSF
ESC - exit
Examples:
deconvolution.py --angle 135 --d 22 licenseplate_motion.jpg
(image source: http://www.topazlabs.com/infocus/_images/licenseplate_compare.jpg)
deconvolution.py --angle 86 --d 31 text_motion.jpg
deconvolution.py --circle --d 19 text_defocus.jpg
(image source: compact digital photo camera, no artificial distortion)
[1] http://en.wikipedia.org/wiki/Wiener_deconvolution
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
# local module
from common import nothing
def blur_edge(img, d=31):
h, w = img.shape[:2]
img_pad = cv.copyMakeBorder(img, d, d, d, d, cv.BORDER_WRAP)
img_blur = cv.GaussianBlur(img_pad, (2*d+1, 2*d+1), -1)[d:-d,d:-d]
y, x = np.indices((h, w))
dist = np.dstack([x, w-x-1, y, h-y-1]).min(-1)
w = np.minimum(np.float32(dist)/d, 1.0)
return img*w + img_blur*(1-w)
def motion_kernel(angle, d, sz=65):
kern = np.ones((1, d), np.float32)
c, s = np.cos(angle), np.sin(angle)
A = np.float32([[c, -s, 0], [s, c, 0]])
sz2 = sz // 2
A[:,2] = (sz2, sz2) - np.dot(A[:,:2], ((d-1)*0.5, 0))
kern = cv.warpAffine(kern, A, (sz, sz), flags=cv.INTER_CUBIC)
return kern
def defocus_kernel(d, sz=65):
kern = np.zeros((sz, sz), np.uint8)
cv.circle(kern, (sz, sz), d, 255, -1, cv.LINE_AA, shift=1)
kern = np.float32(kern) / 255.0
return kern
def main():
import sys, getopt
opts, args = getopt.getopt(sys.argv[1:], '', ['circle', 'angle=', 'd=', 'snr='])
opts = dict(opts)
try:
fn = args[0]
except:
fn = 'licenseplate_motion.jpg'
win = 'deconvolution'
img = cv.imread(cv.samples.findFile(fn), cv.IMREAD_GRAYSCALE)
if img is None:
print('Failed to load file:', fn)
sys.exit(1)
img = np.float32(img)/255.0
cv.imshow('input', img)
img = blur_edge(img)
IMG = cv.dft(img, flags=cv.DFT_COMPLEX_OUTPUT)
defocus = '--circle' in opts
def update(_):
ang = np.deg2rad( cv.getTrackbarPos('angle', win) )
d = cv.getTrackbarPos('d', win)
noise = 10**(-0.1*cv.getTrackbarPos('SNR (db)', win))
if defocus:
psf = defocus_kernel(d)
else:
psf = motion_kernel(ang, d)
cv.imshow('psf', psf)
psf /= psf.sum()
psf_pad = np.zeros_like(img)
kh, kw = psf.shape
psf_pad[:kh, :kw] = psf
PSF = cv.dft(psf_pad, flags=cv.DFT_COMPLEX_OUTPUT, nonzeroRows = kh)
PSF2 = (PSF**2).sum(-1)
iPSF = PSF / (PSF2 + noise)[...,np.newaxis]
RES = cv.mulSpectrums(IMG, iPSF, 0)
res = cv.idft(RES, flags=cv.DFT_SCALE | cv.DFT_REAL_OUTPUT )
res = np.roll(res, -kh//2, 0)
res = np.roll(res, -kw//2, 1)
cv.imshow(win, res)
cv.namedWindow(win)
cv.namedWindow('psf', 0)
cv.createTrackbar('angle', win, int(opts.get('--angle', 135)), 180, update)
cv.createTrackbar('d', win, int(opts.get('--d', 22)), 50, update)
cv.createTrackbar('SNR (db)', win, int(opts.get('--snr', 25)), 50, update)
update(None)
while True:
ch = cv.waitKey()
if ch == 27:
break
if ch == ord(' '):
defocus = not defocus
update(None)
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+193
View File
@@ -0,0 +1,193 @@
#!/usr/bin/env python
'''
Sample-launcher application.
'''
# Python 2/3 compatibility
from __future__ import print_function
import sys
# local modules
from common import splitfn
# built-in modules
import webbrowser
from glob import glob
from subprocess import Popen
try:
import tkinter as tk # Python 3
from tkinter.scrolledtext import ScrolledText
except ImportError:
import Tkinter as tk # Python 2
from ScrolledText import ScrolledText
#from IPython.Shell import IPShellEmbed
#ipshell = IPShellEmbed()
exclude_list = ['demo', 'common']
class LinkManager:
def __init__(self, text, url_callback = None):
self.text = text
self.text.tag_config("link", foreground="blue", underline=1)
self.text.tag_bind("link", "<Enter>", self._enter)
self.text.tag_bind("link", "<Leave>", self._leave)
self.text.tag_bind("link", "<Button-1>", self._click)
self.url_callback = url_callback
self.reset()
def reset(self):
self.links = {}
def add(self, action):
# add an action to the manager. returns tags to use in
# associated text widget
tag = "link-%d" % len(self.links)
self.links[tag] = action
return "link", tag
def _enter(self, event):
self.text.config(cursor="hand2")
def _leave(self, event):
self.text.config(cursor="")
def _click(self, event):
for tag in self.text.tag_names(tk.CURRENT):
if tag.startswith("link-"):
proc = self.links[tag]
if callable(proc):
proc()
else:
if self.url_callback:
self.url_callback(proc)
class App:
def __init__(self):
root = tk.Tk()
root.title('OpenCV Demo')
self.win = win = tk.PanedWindow(root, orient=tk.HORIZONTAL, sashrelief=tk.RAISED, sashwidth=4)
self.win.pack(fill=tk.BOTH, expand=1)
left = tk.Frame(win)
right = tk.Frame(win)
win.add(left)
win.add(right)
scrollbar = tk.Scrollbar(left, orient=tk.VERTICAL)
self.demos_lb = demos_lb = tk.Listbox(left, yscrollcommand=scrollbar.set)
scrollbar.config(command=demos_lb.yview)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
demos_lb.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
self.samples = {}
for fn in glob('*.py'):
name = splitfn(fn)[1]
if fn[0] != '_' and name not in exclude_list:
self.samples[name] = fn
for name in sorted(self.samples):
demos_lb.insert(tk.END, name)
demos_lb.bind('<<ListboxSelect>>', self.on_demo_select)
self.cmd_entry = cmd_entry = tk.Entry(right)
cmd_entry.bind('<Return>', self.on_run)
run_btn = tk.Button(right, command=self.on_run, text='Run', width=8)
self.text = text = ScrolledText(right, font=('arial', 12, 'normal'), width = 30, wrap='word')
self.linker = _linker = LinkManager(text, self.on_link)
self.text.tag_config("header1", font=('arial', 14, 'bold'))
self.text.tag_config("header2", font=('arial', 12, 'bold'))
text.config(state='disabled')
text.pack(fill='both', expand=1, side=tk.BOTTOM)
cmd_entry.pack(fill='x', side='left' , expand=1)
run_btn.pack()
def on_link(self, url):
print(url)
webbrowser.open(url)
def on_demo_select(self, evt):
selection = self.demos_lb.curselection()
if not selection:
return
name = self.demos_lb.get(selection[0])
fn = self.samples[name]
descr = ""
try:
if sys.version_info[0] > 2:
# Python 3.x
module_globals = {}
module_locals = {}
with open(fn, 'r') as f:
module_code = f.read()
exec(compile(module_code, fn, 'exec'), module_globals, module_locals)
descr = module_locals.get('__doc__', 'no-description')
else:
# Python 2
module_globals = {}
execfile(fn, module_globals) # noqa: F821
descr = module_globals.get('__doc__', 'no-description')
except Exception as e:
descr = str(e)
self.linker.reset()
self.text.config(state='normal')
self.text.delete(1.0, tk.END)
self.format_text(descr)
self.text.config(state='disabled')
self.cmd_entry.delete(0, tk.END)
self.cmd_entry.insert(0, fn)
def format_text(self, s):
text = self.text
lines = s.splitlines()
for i, s in enumerate(lines):
s = s.rstrip()
if i == 0 and not s:
continue
if s and s == '='*len(s):
text.tag_add('header1', 'end-2l', 'end-1l')
elif s and s == '-'*len(s):
text.tag_add('header2', 'end-2l', 'end-1l')
else:
text.insert('end', s+'\n')
def add_link(start, end, url):
for tag in self.linker.add(url):
text.tag_add(tag, start, end)
self.match_text(r'http://\S+', add_link)
def match_text(self, pattern, tag_proc, regexp=True):
text = self.text
text.mark_set('matchPos', '1.0')
count = tk.IntVar()
while True:
match_index = text.search(pattern, 'matchPos', count=count, regexp=regexp, stopindex='end')
if not match_index:
break
end_index = text.index( "%s+%sc" % (match_index, count.get()) )
text.mark_set('matchPos', end_index)
if callable(tag_proc):
tag_proc(match_index, end_index, text.get(match_index, end_index))
else:
text.tag_add(tag_proc, match_index, end_index)
def on_run(self, *args):
cmd = self.cmd_entry.get()
print('running:', cmd)
Popen(sys.executable + ' ' + cmd, shell=True)
def run(self):
tk.mainloop()
if __name__ == '__main__':
App().run()
+120
View File
@@ -0,0 +1,120 @@
#!/usr/bin/env python
'''
sample for disctrete fourier transform (dft)
USAGE:
dft.py <image_file>
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
import sys
def shift_dft(src, dst=None):
'''
Rearrange the quadrants of Fourier image so that the origin is at
the image center. Swaps quadrant 1 with 3, and 2 with 4.
src and dst arrays must be equal size & type
'''
if dst is None:
dst = np.empty(src.shape, src.dtype)
elif src.shape != dst.shape:
raise ValueError("src and dst must have equal sizes")
elif src.dtype != dst.dtype:
raise TypeError("src and dst must have equal types")
if src is dst:
ret = np.empty(src.shape, src.dtype)
else:
ret = dst
h, w = src.shape[:2]
cx1 = cx2 = w // 2
cy1 = cy2 = h // 2
# if the size is odd, then adjust the bottom/right quadrants
if w % 2 != 0:
cx2 += 1
if h % 2 != 0:
cy2 += 1
# swap quadrants
# swap q1 and q3
ret[h-cy1:, w-cx1:] = src[0:cy1 , 0:cx1 ] # q1 -> q3
ret[0:cy2 , 0:cx2 ] = src[h-cy2:, w-cx2:] # q3 -> q1
# swap q2 and q4
ret[0:cy2 , w-cx2:] = src[h-cy2:, 0:cx2 ] # q2 -> q4
ret[h-cy1:, 0:cx1 ] = src[0:cy1 , w-cx1:] # q4 -> q2
if src is dst:
dst[:,:] = ret
return dst
def main():
if len(sys.argv) > 1:
fname = sys.argv[1]
else:
fname = 'baboon.jpg'
print("usage : python dft.py <image_file>")
im = cv.imread(cv.samples.findFile(fname))
# convert to grayscale
im = cv.cvtColor(im, cv.COLOR_BGR2GRAY)
h, w = im.shape[:2]
realInput = im.astype(np.float64)
# perform an optimally sized dft
dft_M = cv.getOptimalDFTSize(w)
dft_N = cv.getOptimalDFTSize(h)
# copy A to dft_A and pad dft_A with zeros
dft_A = np.zeros((dft_N, dft_M, 2), dtype=np.float64)
dft_A[:h, :w, 0] = realInput
# no need to pad bottom part of dft_A with zeros because of
# use of nonzeroRows parameter in cv.dft()
cv.dft(dft_A, dst=dft_A, nonzeroRows=h)
cv.imshow("win", im)
# Split fourier into real and imaginary parts
image_Re, image_Im = cv.split(dft_A)
# Compute the magnitude of the spectrum Mag = sqrt(Re^2 + Im^2)
magnitude = cv.sqrt(image_Re**2.0 + image_Im**2.0)
# Compute log(1 + Mag)
log_spectrum = cv.log(1.0 + magnitude)
# Rearrange the quadrants of Fourier image so that the origin is at
# the image center
shift_dft(log_spectrum, log_spectrum)
# normalize and display the results as rgb
cv.normalize(log_spectrum, log_spectrum, 0.0, 1.0, cv.NORM_MINMAX)
cv.imshow("magnitude", log_spectrum)
cv.waitKey(0)
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+194
View File
@@ -0,0 +1,194 @@
#!/usr/bin/env python
'''
SVM and KNearest digit recognition.
Sample loads a dataset of handwritten digits from 'digits.png'.
Then it trains a SVM and KNearest classifiers on it and evaluates
their accuracy.
Following preprocessing is applied to the dataset:
- Moment-based image deskew (see deskew())
- Digit images are split into 4 10x10 cells and 16-bin
histogram of oriented gradients is computed for each
cell
- Transform histograms to space with Hellinger metric (see [1] (RootSIFT))
[1] R. Arandjelovic, A. Zisserman
"Three things everyone should know to improve object retrieval"
http://www.robots.ox.ac.uk/~vgg/publications/2012/Arandjelovic12/arandjelovic12.pdf
Usage:
digits.py
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
# built-in modules
from multiprocessing.pool import ThreadPool
from numpy.linalg import norm
# local modules
from common import clock, mosaic
SZ = 20 # size of each digit is SZ x SZ
CLASS_N = 10
DIGITS_FN = 'digits.png'
def split2d(img, cell_size, flatten=True):
h, w = img.shape[:2]
sx, sy = cell_size
cells = [np.hsplit(row, w//sx) for row in np.vsplit(img, h//sy)]
cells = np.array(cells)
if flatten:
cells = cells.reshape(-1, sy, sx)
return cells
def load_digits(fn):
fn = cv.samples.findFile(fn)
print('loading "%s" ...' % fn)
digits_img = cv.imread(fn, cv.IMREAD_GRAYSCALE)
digits = split2d(digits_img, (SZ, SZ))
labels = np.repeat(np.arange(CLASS_N), len(digits)/CLASS_N)
return digits, labels
def deskew(img):
m = cv.moments(img)
if abs(m['mu02']) < 1e-2:
return img.copy()
skew = m['mu11']/m['mu02']
M = np.float32([[1, skew, -0.5*SZ*skew], [0, 1, 0]])
img = cv.warpAffine(img, M, (SZ, SZ), flags=cv.WARP_INVERSE_MAP | cv.INTER_LINEAR)
return img
class KNearest(object):
def __init__(self, k = 3):
self.k = k
self.model = cv.ml.KNearest_create()
def train(self, samples, responses):
self.model.train(samples, cv.ml.ROW_SAMPLE, responses)
def predict(self, samples):
_retval, results, _neigh_resp, _dists = self.model.findNearest(samples, self.k)
return results.ravel()
def load(self, fn):
self.model = cv.ml.KNearest_load(fn)
def save(self, fn):
self.model.save(fn)
class SVM(object):
def __init__(self, C = 1, gamma = 0.5):
self.model = cv.ml.SVM_create()
self.model.setGamma(gamma)
self.model.setC(C)
self.model.setKernel(cv.ml.SVM_RBF)
self.model.setType(cv.ml.SVM_C_SVC)
def train(self, samples, responses):
self.model.train(samples, cv.ml.ROW_SAMPLE, responses)
def predict(self, samples):
return self.model.predict(samples)[1].ravel()
def load(self, fn):
self.model = cv.ml.SVM_load(fn)
def save(self, fn):
self.model.save(fn)
def evaluate_model(model, digits, samples, labels):
resp = model.predict(samples)
err = (labels != resp).mean()
print('error: %.2f %%' % (err*100))
confusion = np.zeros((10, 10), np.int32)
for i, j in zip(labels, resp):
confusion[i, int(j)] += 1
print('confusion matrix:')
print(confusion)
print()
vis = []
for img, flag in zip(digits, resp == labels):
img = cv.cvtColor(img, cv.COLOR_GRAY2BGR)
if not flag:
img[...,:2] = 0
vis.append(img)
return mosaic(25, vis)
def preprocess_simple(digits):
return np.float32(digits).reshape(-1, SZ*SZ) / 255.0
def preprocess_hog(digits):
samples = []
for img in digits:
gx = cv.Sobel(img, cv.CV_32F, 1, 0)
gy = cv.Sobel(img, cv.CV_32F, 0, 1)
mag, ang = cv.cartToPolar(gx, gy)
bin_n = 16
bin = np.int32(bin_n*ang/(2*np.pi))
bin_cells = bin[:10,:10], bin[10:,:10], bin[:10,10:], bin[10:,10:]
mag_cells = mag[:10,:10], mag[10:,:10], mag[:10,10:], mag[10:,10:]
hists = [np.bincount(b.ravel(), m.ravel(), bin_n) for b, m in zip(bin_cells, mag_cells)]
hist = np.hstack(hists)
# transform to Hellinger kernel
eps = 1e-7
hist /= hist.sum() + eps
hist = np.sqrt(hist)
hist /= norm(hist) + eps
samples.append(hist)
return np.float32(samples)
if __name__ == '__main__':
print(__doc__)
digits, labels = load_digits(DIGITS_FN)
print('preprocessing...')
# shuffle digits
rand = np.random.RandomState(321)
shuffle = rand.permutation(len(digits))
digits, labels = digits[shuffle], labels[shuffle]
digits2 = list(map(deskew, digits))
samples = preprocess_hog(digits2)
train_n = int(0.9*len(samples))
cv.imshow('test set', mosaic(25, digits[train_n:]))
digits_train, digits_test = np.split(digits2, [train_n])
samples_train, samples_test = np.split(samples, [train_n])
labels_train, labels_test = np.split(labels, [train_n])
print('training KNearest...')
model = KNearest(k=4)
model.train(samples_train, labels_train)
vis = evaluate_model(model, digits_test, samples_test, labels_test)
cv.imshow('KNearest test', vis)
print('training SVM...')
model = SVM(C=2.67, gamma=5.383)
model.train(samples_train, labels_train)
vis = evaluate_model(model, digits_test, samples_test, labels_test)
cv.imshow('SVM test', vis)
print('saving SVM as "digits_svm.dat"...')
model.save('digits_svm.dat')
cv.waitKey(0)
cv.destroyAllWindows()
+140
View File
@@ -0,0 +1,140 @@
#!/usr/bin/env python
'''
Digit recognition adjustment.
Grid search is used to find the best parameters for SVM and KNearest classifiers.
SVM adjustment follows the guidelines given in
http://www.csie.ntu.edu.tw/~cjlin/papers/guide/guide.pdf
Usage:
digits_adjust.py [--model {svm|knearest}]
--model {svm|knearest} - select the classifier (SVM is the default)
'''
# Python 2/3 compatibility
from __future__ import print_function
import sys
PY3 = sys.version_info[0] == 3
if PY3:
xrange = range
import numpy as np
import cv2 as cv
from multiprocessing.pool import ThreadPool
from digits import *
def cross_validate(model_class, params, samples, labels, kfold = 3, pool = None):
n = len(samples)
folds = np.array_split(np.arange(n), kfold)
def f(i):
model = model_class(**params)
test_idx = folds[i]
train_idx = list(folds)
train_idx.pop(i)
train_idx = np.hstack(train_idx)
train_samples, train_labels = samples[train_idx], labels[train_idx]
test_samples, test_labels = samples[test_idx], labels[test_idx]
model.train(train_samples, train_labels)
resp = model.predict(test_samples)
score = (resp != test_labels).mean()
print(".", end='')
return score
if pool is None:
scores = list(map(f, xrange(kfold)))
else:
scores = pool.map(f, xrange(kfold))
return np.mean(scores)
class App(object):
def __init__(self):
self._samples, self._labels = self.preprocess()
def preprocess(self):
digits, labels = load_digits(DIGITS_FN)
shuffle = np.random.permutation(len(digits))
digits, labels = digits[shuffle], labels[shuffle]
digits2 = list(map(deskew, digits))
samples = preprocess_hog(digits2)
return samples, labels
def get_dataset(self):
return self._samples, self._labels
def run_jobs(self, f, jobs):
pool = ThreadPool(processes=cv.getNumberOfCPUs())
ires = pool.imap_unordered(f, jobs)
return ires
def adjust_SVM(self):
Cs = np.logspace(0, 10, 15, base=2)
gammas = np.logspace(-7, 4, 15, base=2)
scores = np.zeros((len(Cs), len(gammas)))
scores[:] = np.nan
print('adjusting SVM (may take a long time) ...')
def f(job):
i, j = job
samples, labels = self.get_dataset()
params = dict(C = Cs[i], gamma=gammas[j])
score = cross_validate(SVM, params, samples, labels)
return i, j, score
ires = self.run_jobs(f, np.ndindex(*scores.shape))
for count, (i, j, score) in enumerate(ires):
scores[i, j] = score
print('%d / %d (best error: %.2f %%, last: %.2f %%)' %
(count+1, scores.size, np.nanmin(scores)*100, score*100))
print(scores)
print('writing score table to "svm_scores.npz"')
np.savez('svm_scores.npz', scores=scores, Cs=Cs, gammas=gammas)
i, j = np.unravel_index(scores.argmin(), scores.shape)
best_params = dict(C = Cs[i], gamma=gammas[j])
print('best params:', best_params)
print('best error: %.2f %%' % (scores.min()*100))
return best_params
def adjust_KNearest(self):
print('adjusting KNearest ...')
def f(k):
samples, labels = self.get_dataset()
err = cross_validate(KNearest, dict(k=k), samples, labels)
return k, err
best_err, best_k = np.inf, -1
for k, err in self.run_jobs(f, xrange(1, 9)):
if err < best_err:
best_err, best_k = err, k
print('k = %d, error: %.2f %%' % (k, err*100))
best_params = dict(k=best_k)
print('best params:', best_params, 'err: %.2f' % (best_err*100))
return best_params
if __name__ == '__main__':
import getopt
import sys
print(__doc__)
args, _ = getopt.getopt(sys.argv[1:], '', ['model='])
args = dict(args)
args.setdefault('--model', 'svm')
args.setdefault('--env', '')
if args['--model'] not in ['svm', 'knearest']:
print('unknown model "%s"' % args['--model'])
sys.exit(1)
t = clock()
app = App()
if args['--model'] == 'knearest':
app.adjust_KNearest()
else:
app.adjust_SVM()
print('work time: %f s' % (clock() - t))
+109
View File
@@ -0,0 +1,109 @@
#!/usr/bin/env python
'''
Digit recognition from video.
Run digits.py before, to train and save the SVM.
Usage:
digits_video.py [{camera_id|video_file}]
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
# built-in modules
import os
import sys
# local modules
import video
from common import mosaic
from digits import *
def main():
try:
src = sys.argv[1]
except:
src = 0
cap = video.create_capture(src, fallback='synth:bg={}:noise=0.05'.format(cv.samples.findFile('sudoku.png')))
classifier_fn = 'digits_svm.dat'
if not os.path.exists(classifier_fn):
print('"%s" not found, run digits.py first' % classifier_fn)
return
model = cv.ml.SVM_load(classifier_fn)
while True:
_ret, frame = cap.read()
gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
bin = cv.adaptiveThreshold(gray, 255, cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY_INV, 31, 10)
bin = cv.medianBlur(bin, 3)
contours, heirs = cv.findContours( bin.copy(), cv.RETR_CCOMP, cv.CHAIN_APPROX_SIMPLE)
try:
heirs = heirs[0]
except:
heirs = []
for cnt, heir in zip(contours, heirs):
_, _, _, outer_i = heir
if outer_i >= 0:
continue
x, y, w, h = cv.boundingRect(cnt)
if not (16 <= h <= 64 and w <= 1.2*h):
continue
pad = max(h-w, 0)
x, w = x - (pad // 2), w + pad
cv.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0))
bin_roi = bin[y:,x:][:h,:w]
m = bin_roi != 0
if not 0.1 < m.mean() < 0.4:
continue
'''
gray_roi = gray[y:,x:][:h,:w]
v_in, v_out = gray_roi[m], gray_roi[~m]
if v_out.std() > 10.0:
continue
s = "%f, %f" % (abs(v_in.mean() - v_out.mean()), v_out.std())
cv.putText(frame, s, (x, y), cv.FONT_HERSHEY_PLAIN, 1.0, (200, 0, 0), thickness = 1)
'''
s = 1.5*float(h)/SZ
m = cv.moments(bin_roi)
c1 = np.float32([m['m10'], m['m01']]) / m['m00']
c0 = np.float32([SZ/2, SZ/2])
t = c1 - s*c0
A = np.zeros((2, 3), np.float32)
A[:,:2] = np.eye(2)*s
A[:,2] = t
bin_norm = cv.warpAffine(bin_roi, A, (SZ, SZ), flags=cv.WARP_INVERSE_MAP | cv.INTER_LINEAR)
bin_norm = deskew(bin_norm)
if x+w+SZ < frame.shape[1] and y+SZ < frame.shape[0]:
frame[y:,x+w:][:SZ, :SZ] = bin_norm[...,np.newaxis]
sample = preprocess_hog([bin_norm])
digit = model.predict(sample)[1].ravel()
cv.putText(frame, '%d'%digit, (x, y), cv.FONT_HERSHEY_PLAIN, 1.0, (200, 0, 0), thickness = 1)
cv.imshow('frame', frame)
cv.imshow('bin', bin)
ch = cv.waitKey(1)
if ch == 27:
break
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+122
View File
@@ -0,0 +1,122 @@
#!/usr/bin/env python
'''
example to show optical flow estimation using DISOpticalFlow
USAGE: dis_opt_flow.py [<video_source>]
Keys:
1 - toggle HSV flow visualization
2 - toggle glitch
3 - toggle spatial propagation of flow vectors
4 - toggle temporal propagation of flow vectors
ESC - exit
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
import video
def draw_flow(img, flow, step=16):
h, w = img.shape[:2]
y, x = np.mgrid[step/2:h:step, step/2:w:step].reshape(2,-1).astype(int)
fx, fy = flow[y,x].T
lines = np.vstack([x, y, x+fx, y+fy]).T.reshape(-1, 2, 2)
lines = np.int32(lines + 0.5)
vis = cv.cvtColor(img, cv.COLOR_GRAY2BGR)
cv.polylines(vis, lines, 0, (0, 255, 0))
for (x1, y1), (_x2, _y2) in lines:
cv.circle(vis, (x1, y1), 1, (0, 255, 0), -1)
return vis
def draw_hsv(flow):
h, w = flow.shape[:2]
fx, fy = flow[:,:,0], flow[:,:,1]
ang = np.arctan2(fy, fx) + np.pi
v = np.sqrt(fx*fx+fy*fy)
hsv = np.zeros((h, w, 3), np.uint8)
hsv[...,0] = ang*(180/np.pi/2)
hsv[...,1] = 255
hsv[...,2] = np.minimum(v*4, 255)
bgr = cv.cvtColor(hsv, cv.COLOR_HSV2BGR)
return bgr
def warp_flow(img, flow):
h, w = flow.shape[:2]
flow = -flow
flow[:,:,0] += np.arange(w)
flow[:,:,1] += np.arange(h)[:,np.newaxis]
res = cv.remap(img, flow, None, cv.INTER_LINEAR)
return res
def main():
import sys
print(__doc__)
try:
fn = sys.argv[1]
except IndexError:
fn = 0
cam = video.create_capture(fn)
_ret, prev = cam.read()
prevgray = cv.cvtColor(prev, cv.COLOR_BGR2GRAY)
show_hsv = False
show_glitch = False
use_spatial_propagation = False
use_temporal_propagation = True
cur_glitch = prev.copy()
inst = cv.DISOpticalFlow.create(cv.DISOPTICAL_FLOW_PRESET_MEDIUM)
inst.setUseSpatialPropagation(use_spatial_propagation)
flow = None
while True:
_ret, img = cam.read()
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
if flow is not None and use_temporal_propagation:
#warp previous flow to get an initial approximation for the current flow:
flow = inst.calc(prevgray, gray, warp_flow(flow,flow))
else:
flow = inst.calc(prevgray, gray, None)
prevgray = gray
cv.imshow('flow', draw_flow(gray, flow))
if show_hsv:
cv.imshow('flow HSV', draw_hsv(flow))
if show_glitch:
cur_glitch = warp_flow(cur_glitch, flow)
cv.imshow('glitch', cur_glitch)
ch = 0xFF & cv.waitKey(5)
if ch == 27:
break
if ch == ord('1'):
show_hsv = not show_hsv
print('HSV flow visualization is', ['off', 'on'][show_hsv])
if ch == ord('2'):
show_glitch = not show_glitch
if show_glitch:
cur_glitch = img.copy()
print('glitch is', ['off', 'on'][show_glitch])
if ch == ord('3'):
use_spatial_propagation = not use_spatial_propagation
inst.setUseSpatialPropagation(use_spatial_propagation)
print('spatial propagation is', ['off', 'on'][use_spatial_propagation])
if ch == ord('4'):
use_temporal_propagation = not use_temporal_propagation
print('temporal propagation is', ['off', 'on'][use_temporal_propagation])
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+78
View File
@@ -0,0 +1,78 @@
#!/usr/bin/env python
'''
Distance transform sample.
Usage:
distrans.py [<image>]
Keys:
ESC - exit
v - toggle voronoi mode
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
from common import make_cmap
def main():
import sys
try:
fn = sys.argv[1]
except:
fn = 'fruits.jpg'
fn = cv.samples.findFile(fn)
img = cv.imread(fn, cv.IMREAD_GRAYSCALE)
if img is None:
print('Failed to load fn:', fn)
sys.exit(1)
cm = make_cmap('jet')
need_update = True
voronoi = False
def update(dummy=None):
global need_update
need_update = False
thrs = cv.getTrackbarPos('threshold', 'distrans')
mark = cv.Canny(img, thrs, 3*thrs)
dist, labels = cv.distanceTransformWithLabels(~mark, cv.DIST_L2, 5)
if voronoi:
vis = cm[np.uint8(labels)]
else:
vis = cm[np.uint8(dist*2)]
vis[mark != 0] = 255
cv.imshow('distrans', vis)
def invalidate(dummy=None):
global need_update
need_update = True
cv.namedWindow('distrans')
cv.createTrackbar('threshold', 'distrans', 60, 255, invalidate)
update()
while True:
ch = cv.waitKey(50)
if ch == 27:
break
if ch == ord('v'):
voronoi = not voronoi
print('showing', ['distance', 'voronoi'][voronoi])
update()
if need_update:
update()
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+191
View File
@@ -0,0 +1,191 @@
#!/usr/bin/env python
'''
This program demonstrates OpenCV drawing and text output functions by drawing different shapes and text strings
Usage :
python3 drawing.py
Press any button to exit
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
# Drawing Lines
def lines():
for i in range(NUMBER*2):
pt1, pt2 = [], []
pt1.append(np.random.randint(x1, x2))
pt1.append(np.random.randint(y1, y2))
pt2.append(np.random.randint(x1, x2))
pt2.append(np.random.randint(y1, y2))
color = "%06x" % np.random.randint(0, 0xFFFFFF)
color = tuple(int(color[i:i+2], 16) for i in (0, 2 ,4))
arrowed = np.random.randint(0, 6)
if (arrowed<3):
cv.line(image, tuple(pt1), tuple(pt2), color, np.random.randint(1, 10), lineType)
else:
cv.arrowedLine(image, tuple(pt1), tuple(pt2), color, np.random.randint(1, 10), lineType)
cv.imshow(wndname, image)
if cv.waitKey(DELAY)>=0:
return
# Drawing Rectangle
def rectangle():
for i in range(NUMBER*2):
pt1, pt2 = [], []
pt1.append(np.random.randint(x1, x2))
pt1.append(np.random.randint(y1, y2))
pt2.append(np.random.randint(x1, x2))
pt2.append(np.random.randint(y1, y2))
color = "%06x" % np.random.randint(0, 0xFFFFFF)
color = tuple(int(color[i:i+2], 16) for i in (0, 2 ,4))
thickness = np.random.randint(-3, 10)
marker = np.random.randint(0, 10)
marker_size = np.random.randint(30, 80)
if (marker > 5):
cv.rectangle(image, tuple(pt1), tuple(pt2), color, max(thickness, -1), lineType)
else:
cv.drawMarker(image, tuple(pt1), color, marker, marker_size)
cv.imshow(wndname, image)
if cv.waitKey(DELAY)>=0:
return
# Drawing ellipse
def ellipse():
for i in range(NUMBER*2):
center = []
center.append(np.random.randint(x1, x2))
center.append(np.random.randint(y1, y2))
axes = []
axes.append(np.random.randint(0, 200))
axes.append(np.random.randint(0, 200))
angle = np.random.randint(0, 180)
color = "%06x" % np.random.randint(0, 0xFFFFFF)
color = tuple(int(color[i:i+2], 16) for i in (0, 2 ,4))
thickness = np.random.randint(-1, 9)
cv.ellipse(image, tuple(center), tuple(axes), angle, angle-100, angle + 200, color, thickness, lineType)
cv.imshow(wndname, image)
if cv.waitKey(DELAY)>=0:
return
# Drawing Polygonal Curves
def polygonal():
for i in range(NUMBER):
pt = [(0, 0)]*6
pt = np.resize(pt, (2, 3, 2))
pt[0][0][0] = np.random.randint(x1, x2)
pt[0][0][1] = np.random.randint(y1, y2)
pt[0][1][0] = np.random.randint(x1, x2)
pt[0][1][1] = np.random.randint(y1, y2)
pt[0][2][0] = np.random.randint(x1, x2)
pt[0][2][1] = np.random.randint(y1, y2)
pt[1][0][0] = np.random.randint(x1, x2)
pt[1][0][1] = np.random.randint(y1, y2)
pt[1][1][0] = np.random.randint(x1, x2)
pt[1][1][1] = np.random.randint(y1, y2)
pt[1][2][0] = np.random.randint(x1, x2)
pt[1][2][1] = np.random.randint(y1, y2)
color = "%06x" % np.random.randint(0, 0xFFFFFF)
color = tuple(int(color[i:i+2], 16) for i in (0, 2 ,4))
alist = []
for k in pt[0]:
alist.append(k)
for k in pt[1]:
alist.append(k)
ppt = np.array(alist)
cv.polylines(image, [ppt], True, color, thickness = np.random.randint(1, 10), lineType = lineType)
cv.imshow(wndname, image)
if cv.waitKey(DELAY) >= 0:
return
# fills an area bounded by several polygonal contours
def fill():
for i in range(NUMBER):
pt = [(0, 0)]*6
pt = np.resize(pt, (2, 3, 2))
pt[0][0][0] = np.random.randint(x1, x2)
pt[0][0][1] = np.random.randint(y1, y2)
pt[0][1][0] = np.random.randint(x1, x2)
pt[0][1][1] = np.random.randint(y1, y2)
pt[0][2][0] = np.random.randint(x1, x2)
pt[0][2][1] = np.random.randint(y1, y2)
pt[1][0][0] = np.random.randint(x1, x2)
pt[1][0][1] = np.random.randint(y1, y2)
pt[1][1][0] = np.random.randint(x1, x2)
pt[1][1][1] = np.random.randint(y1, y2)
pt[1][2][0] = np.random.randint(x1, x2)
pt[1][2][1] = np.random.randint(y1, y2)
color = "%06x" % np.random.randint(0, 0xFFFFFF)
color = tuple(int(color[i:i+2], 16) for i in (0, 2 ,4))
alist = []
for k in pt[0]:
alist.append(k)
for k in pt[1]:
alist.append(k)
ppt = np.array(alist)
cv.fillPoly(image, [ppt], color, lineType)
cv.imshow(wndname, image)
if cv.waitKey(DELAY) >= 0:
return
# Drawing Circles
def circles():
for i in range(NUMBER):
center = []
center.append(np.random.randint(x1, x2))
center.append(np.random.randint(y1, y2))
color = "%06x" % np.random.randint(0, 0xFFFFFF)
color = tuple(int(color[i:i+2], 16) for i in (0, 2 ,4))
cv.circle(image, tuple(center), np.random.randint(0, 300), color, np.random.randint(-1, 9), lineType)
cv.imshow(wndname, image)
if cv.waitKey(DELAY) >= 0:
return
# Draws a text string
def string():
for i in range(NUMBER):
org = []
org.append(np.random.randint(x1, x2))
org.append(np.random.randint(y1, y2))
color = "%06x" % np.random.randint(0, 0xFFFFFF)
color = tuple(int(color[i:i+2], 16) for i in (0, 2 ,4))
cv.putText(image, "Testing text rendering", tuple(org), np.random.randint(0, 8), np.random.randint(0, 100)*0.05+0.1, color, np.random.randint(1, 10), lineType)
cv.imshow(wndname, image)
if cv.waitKey(DELAY) >= 0:
return
def string1():
textsize = cv.getTextSize("OpenCV forever!", cv.FONT_HERSHEY_COMPLEX, 3, 5)
org = (int((width - textsize[0][0])/2), int((height - textsize[0][1])/2))
for i in range(0, 255, 2):
image2 = np.array(image) - i
cv.putText(image2, "OpenCV forever!", org, cv.FONT_HERSHEY_COMPLEX, 3, (i, i, 255), 5, lineType)
cv.imshow(wndname, image2)
if cv.waitKey(DELAY) >= 0:
return
if __name__ == '__main__':
print(__doc__)
wndname = "Drawing Demo"
NUMBER = 100
DELAY = 5
width, height = 1000, 700
lineType = cv.LINE_AA # change it to LINE_8 to see non-antialiased graphics
x1, x2, y1, y2 = -width/2, width*3/2, -height/2, height*3/2
image = np.zeros((height, width, 3), dtype = np.uint8)
cv.imshow(wndname, image)
cv.waitKey(DELAY)
lines()
rectangle()
ellipse()
polygonal()
fill()
circles()
string()
string1()
cv.waitKey(0)
cv.destroyAllWindows()
+60
View File
@@ -0,0 +1,60 @@
#!/usr/bin/env python
'''
This sample demonstrates Canny edge detection.
Usage:
edge.py [<video source>]
Trackbars control edge thresholds.
'''
# Python 2/3 compatibility
from __future__ import print_function
import cv2 as cv
import numpy as np
# relative module
import video
# built-in module
import sys
def main():
try:
fn = sys.argv[1]
except:
fn = 0
def nothing(*arg):
pass
cv.namedWindow('edge')
cv.createTrackbar('thrs1', 'edge', 2000, 5000, nothing)
cv.createTrackbar('thrs2', 'edge', 4000, 5000, nothing)
cap = video.create_capture(fn)
while True:
_flag, img = cap.read()
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
thrs1 = cv.getTrackbarPos('thrs1', 'edge')
thrs2 = cv.getTrackbarPos('thrs2', 'edge')
edge = cv.Canny(gray, thrs1, thrs2, apertureSize=5)
vis = img.copy()
vis = np.uint8(vis/2.)
vis[edge != 0] = (0, 255, 0)
cv.imshow('edge', vis)
ch = cv.waitKey(5)
if ch == 27:
break
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+137
View File
@@ -0,0 +1,137 @@
import numpy as np, cv2 as cv, matplotlib.pyplot as plt, time, sys, os
from mpl_toolkits.mplot3d import axes3d, Axes3D
def getEpipolarError(F, pts1_, pts2_, inliers):
pts1 = np.concatenate((pts1_.T, np.ones((1, pts1_.shape[0]))))[:,inliers]
pts2 = np.concatenate((pts2_.T, np.ones((1, pts2_.shape[0]))))[:,inliers]
lines2 = np.dot(F , pts1)
lines1 = np.dot(F.T, pts2)
return np.median((np.abs(np.sum(pts1 * lines1, axis=0)) / np.sqrt(lines1[0,:]**2 + lines1[1,:]**2) +
np.abs(np.sum(pts2 * lines2, axis=0)) / np.sqrt(lines2[0,:]**2 + lines2[1,:]**2))/2)
if __name__ == '__main__':
if len(sys.argv) < 3:
print("Path to data file and directory to image files are missing!\nData file must have"
" format:\n--------------\n image_name_1\nimage_name_2\nk11 k12 k13\n0 k22 k23\n"
"0 0 1\n--------------\nIf image_name_{1,2} are not in the same directory as "
"the data file then add argument with directory to image files.\nFor example: "
"python essential_mat_reconstr.py essential_mat_data.txt ./")
exit(1)
else:
data_file = sys.argv[1]
image_dir = sys.argv[2]
if not os.path.isfile(data_file):
print('Incorrect path to data file!')
exit(1)
with open(data_file, 'r') as f:
image1 = cv.imread(image_dir+f.readline()[:-1]) # remove '\n'
image2 = cv.imread(image_dir+f.readline()[:-1])
K = np.array([[float(x) for x in f.readline().split(' ')],
[float(x) for x in f.readline().split(' ')],
[float(x) for x in f.readline().split(' ')]])
if image1 is None or image2 is None:
print('Incorrect directory to images!')
exit(1)
if K.shape != (3,3):
print('Intrinsic matrix has incorrect format!')
exit(1)
print('find keypoints and compute descriptors')
detector = cv.SIFT_create(nfeatures=20000)
keypoints1, descriptors1 = detector.detectAndCompute(cv.cvtColor(image1, cv.COLOR_BGR2GRAY), None)
keypoints2, descriptors2 = detector.detectAndCompute(cv.cvtColor(image2, cv.COLOR_BGR2GRAY), None)
matcher = cv.FlannBasedMatcher(dict(algorithm=0, trees=5), dict(checks=32))
print('match with FLANN, size of descriptors', descriptors1.shape, descriptors2.shape)
matches_vector = matcher.knnMatch(descriptors1, descriptors2, k=2)
print('find good keypoints')
pts1 = []; pts2 = []
for m in matches_vector:
# compare best and second match using Lowe ratio test
if m[0].distance / m[1].distance < 0.75:
pts1.append(keypoints1[m[0].queryIdx].pt)
pts2.append(keypoints2[m[0].trainIdx].pt)
pts1 = np.array(pts1); pts2 = np.array(pts2)
print('points size', pts1.shape[0])
print('Essential matrix RANSAC')
start = time.time()
E, inliers = cv.findEssentialMat(pts1, pts2, K, cv.RANSAC, 0.999, 1.0)
print('RANSAC time', time.time() - start, 'seconds')
print('Median error to epipolar lines', getEpipolarError
(np.dot(np.linalg.inv(K).T, np.dot(E, np.linalg.inv(K))), pts1, pts2, inliers.squeeze()),
'number of inliers', inliers.sum())
print('Decompose essential matrix')
R1, R2, t = cv.decomposeEssentialMat(E)
# Assume relative pose. Fix the first camera
P1 = np.concatenate((K, np.zeros((3,1))), axis=1) # K [I | 0]
P2s = [np.dot(K, np.concatenate((R1, t), axis=1)), # K[R1 | t]
np.dot(K, np.concatenate((R1, -t), axis=1)), # K[R1 | -t]
np.dot(K, np.concatenate((R2, t), axis=1)), # K[R2 | t]
np.dot(K, np.concatenate((R2, -t), axis=1))] # K[R2 | -t]
obj_pts_per_cam = []
# enumerate over all P2 projection matrices
for cam_idx, P2 in enumerate(P2s):
obj_pts = []
for i, (pt1, pt2) in enumerate(zip(pts1, pts2)):
if not inliers[i]:
continue
# find object point by triangulation of image points by projection matrices
obj_pt = cv.triangulatePoints(P1, P2, pt1, pt2)
obj_pt /= obj_pt[3]
# check if reprojected point has positive depth
if obj_pt[2] > 0:
obj_pts.append([obj_pt[0], obj_pt[1], obj_pt[2]])
obj_pts_per_cam.append(obj_pts)
best_cam_idx = np.array([len(obj_pts_per_cam[0]),len(obj_pts_per_cam[1]),
len(obj_pts_per_cam[2]),len(obj_pts_per_cam[3])]).argmax()
max_pts = len(obj_pts_per_cam[best_cam_idx])
print('Number of object points', max_pts)
# filter object points to have reasonable depth
MAX_DEPTH = 6.
obj_pts = []
for pt in obj_pts_per_cam[best_cam_idx]:
if pt[2] < MAX_DEPTH:
obj_pts.append(pt)
obj_pts = np.array(obj_pts).reshape(len(obj_pts), 3)
# visualize image points
for i, (pt1, pt2) in enumerate(zip(pts1, pts2)):
if inliers[i]:
cv.circle(image1, (int(pt1[0]), int(pt1[1])), 7, (255,0,0), -1)
cv.circle(image2, (int(pt2[0]), int(pt2[1])), 7, (255,0,0), -1)
# concatenate two images
image1 = np.concatenate((image1, image2), axis=1)
# resize concatenated image
new_img_size = 1200. * 800.
image1 = cv.resize(image1, (int(np.sqrt(image1.shape[1] * new_img_size / image1.shape[0])),
int(np.sqrt (image1.shape[0] * new_img_size / image1.shape[1]))))
# plot object points
fig = plt.figure(figsize=(13.0, 11.0))
ax = fig.add_subplot(111, projection='3d')
ax.set_aspect('equal')
ax.scatter(obj_pts[:,0], obj_pts[:,1], obj_pts[:,2], c='r', marker='o', s=3)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('depth')
ax.view_init(azim=-80, elev=110)
# save figures
cv.imshow("matches", image1)
cv.imwrite('matches_E.png', image1)
plt.savefig('reconstruction_3D.png')
cv.waitKey(0)
plt.show()
+79
View File
@@ -0,0 +1,79 @@
#!/usr/bin/env python
'''
face detection using haar cascades
USAGE:
facedetect.py [--cascade <cascade_fn>] [--nested-cascade <cascade_fn>] [<video_source>]
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
# local modules
from video import create_capture
from common import clock, draw_str
def detect(img, cascade):
rects = cascade.detectMultiScale(img, scaleFactor=1.3, minNeighbors=4, minSize=(30, 30),
flags=cv.CASCADE_SCALE_IMAGE)
if len(rects) == 0:
return []
rects[:,2:] += rects[:,:2]
return rects
def draw_rects(img, rects, color):
for x1, y1, x2, y2 in rects:
cv.rectangle(img, (x1, y1), (x2, y2), color, 2)
def main():
import sys, getopt
args, video_src = getopt.getopt(sys.argv[1:], '', ['cascade=', 'nested-cascade='])
try:
video_src = video_src[0]
except:
video_src = 0
args = dict(args)
cascade_fn = args.get('--cascade', "haarcascades/haarcascade_frontalface_alt.xml")
nested_fn = args.get('--nested-cascade', "haarcascades/haarcascade_eye.xml")
cascade = cv.CascadeClassifier(cv.samples.findFile(cascade_fn))
nested = cv.CascadeClassifier(cv.samples.findFile(nested_fn))
cam = create_capture(video_src, fallback='synth:bg={}:noise=0.05'.format(cv.samples.findFile('lena.jpg')))
while True:
_ret, img = cam.read()
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
gray = cv.equalizeHist(gray)
t = clock()
rects = detect(gray, cascade)
vis = img.copy()
draw_rects(vis, rects, (0, 255, 0))
if not nested.empty():
for x1, y1, x2, y2 in rects:
roi = gray[y1:y2, x1:x2]
vis_roi = vis[y1:y2, x1:x2]
subrects = detect(roi.copy(), nested)
draw_rects(vis_roi, subrects, (255, 0, 0))
dt = clock() - t
draw_str(vis, (20, 20), 'time: %.1f ms' % (dt*1000))
cv.imshow('facedetect', vis)
if cv.waitKey(5) == 27:
break
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+98
View File
@@ -0,0 +1,98 @@
#!/usr/bin/env python
'''
Feature homography
==================
Example of using features2d framework for interactive video homography matching.
ORB features and FLANN matcher are used. The actual tracking is implemented by
PlaneTracker class in plane_tracker.py
Inspired by http://www.youtube.com/watch?v=-ZNYoL8rzPY
video: http://www.youtube.com/watch?v=FirtmYcC0Vc
Usage
-----
feature_homography.py [<video source>]
Keys:
SPACE - pause video
Select a textured planar object to track by drawing a box with a mouse.
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
# local modules
import video
from video import presets
import common
from common import getsize, draw_keypoints
from plane_tracker import PlaneTracker
class App:
def __init__(self, src):
self.cap = video.create_capture(src, presets['book'])
self.frame = None
self.paused = False
self.tracker = PlaneTracker()
cv.namedWindow('plane')
self.rect_sel = common.RectSelector('plane', self.on_rect)
def on_rect(self, rect):
self.tracker.clear()
self.tracker.add_target(self.frame, rect)
def run(self):
while True:
playing = not self.paused and not self.rect_sel.dragging
if playing or self.frame is None:
ret, frame = self.cap.read()
if not ret:
break
self.frame = frame.copy()
w, h = getsize(self.frame)
vis = np.zeros((h, w*2, 3), np.uint8)
vis[:h,:w] = self.frame
if len(self.tracker.targets) > 0:
target = self.tracker.targets[0]
vis[:,w:] = target.image
draw_keypoints(vis[:,w:], target.keypoints)
x0, y0, x1, y1 = target.rect
cv.rectangle(vis, (x0+w, y0), (x1+w, y1), (0, 255, 0), 2)
if playing:
tracked = self.tracker.track(self.frame)
if len(tracked) > 0:
tracked = tracked[0]
cv.polylines(vis, [np.int32(tracked.quad)], True, (255, 255, 255), 2)
for (x0, y0), (x1, y1) in zip(np.int32(tracked.p0), np.int32(tracked.p1)):
cv.line(vis, (x0+w, y0), (x1, y1), (0, 255, 0))
draw_keypoints(vis, self.tracker.frame_points)
self.rect_sel.draw(vis)
cv.imshow('plane', vis)
ch = cv.waitKey(1)
if ch == ord(' '):
self.paused = not self.paused
if ch == 27:
break
if __name__ == '__main__':
print(__doc__)
import sys
try:
video_src = sys.argv[1]
except:
video_src = 0
App(video_src).run()
+197
View File
@@ -0,0 +1,197 @@
#!/usr/bin/env python
'''
Feature-based image matching sample.
Note, that you will need the https://github.com/opencv/opencv_contrib repo for SIFT and SURF
USAGE
find_obj.py [--feature=<sift|surf|orb|akaze|brisk>[-flann]] [ <image1> <image2> ]
--feature - Feature to use. Can be sift, surf, orb or brisk. Append '-flann'
to feature name to use Flann-based matcher instead bruteforce.
Press left mouse button on a feature point to see its matching point.
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
from common import anorm, getsize
FLANN_INDEX_KDTREE = 1 # bug: flann enums are missing
FLANN_INDEX_LSH = 6
def init_feature(name):
chunks = name.split('-')
if chunks[0] == 'sift':
detector = cv.SIFT_create()
norm = cv.NORM_L2
elif chunks[0] == 'surf':
detector = cv.xfeatures2d.SURF_create(800)
norm = cv.NORM_L2
elif chunks[0] == 'orb':
detector = cv.ORB_create(400)
norm = cv.NORM_HAMMING
elif chunks[0] == 'akaze':
detector = cv.AKAZE_create()
norm = cv.NORM_HAMMING
elif chunks[0] == 'brisk':
detector = cv.BRISK_create()
norm = cv.NORM_HAMMING
else:
return None, None
if 'flann' in chunks:
if norm == cv.NORM_L2:
flann_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
else:
flann_params= dict(algorithm = FLANN_INDEX_LSH,
table_number = 6, # 12
key_size = 12, # 20
multi_probe_level = 1) #2
matcher = cv.FlannBasedMatcher(flann_params, {}) # bug : need to pass empty dict (#1329)
else:
matcher = cv.BFMatcher(norm)
return detector, matcher
def filter_matches(kp1, kp2, matches, ratio = 0.75):
mkp1, mkp2 = [], []
for m in matches:
if len(m) == 2 and m[0].distance < m[1].distance * ratio:
m = m[0]
mkp1.append( kp1[m.queryIdx] )
mkp2.append( kp2[m.trainIdx] )
p1 = np.float32([kp.pt for kp in mkp1])
p2 = np.float32([kp.pt for kp in mkp2])
kp_pairs = zip(mkp1, mkp2)
return p1, p2, list(kp_pairs)
def explore_match(win, img1, img2, kp_pairs, status = None, H = None):
h1, w1 = img1.shape[:2]
h2, w2 = img2.shape[:2]
vis = np.zeros((max(h1, h2), w1+w2), np.uint8)
vis[:h1, :w1] = img1
vis[:h2, w1:w1+w2] = img2
vis = cv.cvtColor(vis, cv.COLOR_GRAY2BGR)
if H is not None:
corners = np.float32([[0, 0], [w1, 0], [w1, h1], [0, h1]])
corners = np.int32( cv.perspectiveTransform(corners.reshape(1, -1, 2), H).reshape(-1, 2) + (w1, 0) )
cv.polylines(vis, [corners], True, (255, 255, 255))
if status is None:
status = np.ones(len(kp_pairs), np.bool_)
status = status.reshape((len(kp_pairs), 1))
p1, p2 = [], [] # python 2 / python 3 change of zip unpacking
for kpp in kp_pairs:
p1.append(np.int32(kpp[0].pt))
p2.append(np.int32(np.array(kpp[1].pt) + [w1, 0]))
green = (0, 255, 0)
red = (0, 0, 255)
kp_color = (51, 103, 236)
for (x1, y1), (x2, y2), inlier in zip(p1, p2, status):
if inlier:
col = green
cv.circle(vis, (x1, y1), 2, col, -1)
cv.circle(vis, (x2, y2), 2, col, -1)
else:
col = red
r = 2
thickness = 3
cv.line(vis, (x1-r, y1-r), (x1+r, y1+r), col, thickness)
cv.line(vis, (x1-r, y1+r), (x1+r, y1-r), col, thickness)
cv.line(vis, (x2-r, y2-r), (x2+r, y2+r), col, thickness)
cv.line(vis, (x2-r, y2+r), (x2+r, y2-r), col, thickness)
vis0 = vis.copy()
for (x1, y1), (x2, y2), inlier in zip(p1, p2, status):
if inlier:
cv.line(vis, (x1, y1), (x2, y2), green)
cv.imshow(win, vis)
def onmouse(event, x, y, flags, param):
cur_vis = vis
if flags & cv.EVENT_FLAG_LBUTTON:
cur_vis = vis0.copy()
r = 8
m = (anorm(np.array(p1) - (x, y)) < r) | (anorm(np.array(p2) - (x, y)) < r)
idxs = np.where(m)[0]
kp1s, kp2s = [], []
for i in idxs:
(x1, y1), (x2, y2) = p1[i], p2[i]
col = (red, green)[status[i][0]]
cv.line(cur_vis, (x1, y1), (x2, y2), col)
kp1, kp2 = kp_pairs[i]
kp1s.append(kp1)
kp2s.append(kp2)
cur_vis = cv.drawKeypoints(cur_vis, kp1s, None, flags=4, color=kp_color)
cur_vis[:,w1:] = cv.drawKeypoints(cur_vis[:,w1:], kp2s, None, flags=4, color=kp_color)
cv.imshow(win, cur_vis)
cv.setMouseCallback(win, onmouse)
return vis
def main():
import sys, getopt
opts, args = getopt.getopt(sys.argv[1:], '', ['feature='])
opts = dict(opts)
feature_name = opts.get('--feature', 'brisk')
try:
fn1, fn2 = args
except:
fn1 = 'box.png'
fn2 = 'box_in_scene.png'
img1 = cv.imread(cv.samples.findFile(fn1), cv.IMREAD_GRAYSCALE)
img2 = cv.imread(cv.samples.findFile(fn2), cv.IMREAD_GRAYSCALE)
detector, matcher = init_feature(feature_name)
if img1 is None:
print('Failed to load fn1:', fn1)
sys.exit(1)
if img2 is None:
print('Failed to load fn2:', fn2)
sys.exit(1)
if detector is None:
print('unknown feature:', feature_name)
sys.exit(1)
print('using', feature_name)
kp1, desc1 = detector.detectAndCompute(img1, None)
kp2, desc2 = detector.detectAndCompute(img2, None)
print('img1 - %d features, img2 - %d features' % (len(kp1), len(kp2)))
def match_and_draw(win):
print('matching...')
raw_matches = matcher.knnMatch(desc1, trainDescriptors = desc2, k = 2) #2
p1, p2, kp_pairs = filter_matches(kp1, kp2, raw_matches)
if len(p1) >= 4:
H, status = cv.findHomography(p1, p2, cv.RANSAC, 5.0)
print('%d / %d inliers/matched' % (np.sum(status), len(status)))
else:
H, status = None, None
print('%d matches found, not enough for homography estimation' % len(p1))
_vis = explore_match(win, img1, img2, kp_pairs, status, H)
match_and_draw('find_obj')
cv.waitKey()
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+105
View File
@@ -0,0 +1,105 @@
#!/usr/bin/env python
'''
Robust line fitting.
==================
Example of using cv.fitLine function for fitting line
to points in presence of outliers.
Usage
-----
fitline.py
Switch through different M-estimator functions and see,
how well the robust functions fit the line even
in case of ~50% of outliers.
Keys
----
SPACE - generate random points
f - change distance function
ESC - exit
'''
# Python 2/3 compatibility
from __future__ import print_function
import sys
PY3 = sys.version_info[0] == 3
import numpy as np
import cv2 as cv
# built-in modules
import itertools as it
# local modules
from common import draw_str
w, h = 512, 256
def toint(p):
return tuple(map(int, p))
def sample_line(p1, p2, n, noise=0.0):
p1 = np.float32(p1)
t = np.random.rand(n,1)
return p1 + (p2-p1)*t + np.random.normal(size=(n, 2))*noise
dist_func_names = it.cycle('DIST_L2 DIST_L1 DIST_L12 DIST_FAIR DIST_WELSCH DIST_HUBER'.split())
if PY3:
cur_func_name = next(dist_func_names)
else:
cur_func_name = dist_func_names.next()
def update(_=None):
noise = cv.getTrackbarPos('noise', 'fit line')
n = cv.getTrackbarPos('point n', 'fit line')
r = cv.getTrackbarPos('outlier %', 'fit line') / 100.0
outn = int(n*r)
p0, p1 = (90, 80), (w-90, h-80)
img = np.zeros((h, w, 3), np.uint8)
cv.line(img, toint(p0), toint(p1), (0, 255, 0))
if n > 0:
line_points = sample_line(p0, p1, n-outn, noise)
outliers = np.random.rand(outn, 2) * (w, h)
points = np.vstack([line_points, outliers])
for p in line_points:
cv.circle(img, toint(p), 2, (255, 255, 255), -1)
for p in outliers:
cv.circle(img, toint(p), 2, (64, 64, 255), -1)
func = getattr(cv, cur_func_name)
vx, vy, cx, cy = cv.fitLine(np.float32(points), func, 0, 0.01, 0.01)
cv.line(img, (int(cx-vx*w), int(cy-vy*w)), (int(cx+vx*w), int(cy+vy*w)), (0, 0, 255))
draw_str(img, (20, 20), cur_func_name)
cv.imshow('fit line', img)
def main():
cv.namedWindow('fit line')
cv.createTrackbar('noise', 'fit line', 3, 50, update)
cv.createTrackbar('point n', 'fit line', 100, 500, update)
cv.createTrackbar('outlier %', 'fit line', 30, 100, update)
while True:
update()
ch = cv.waitKey(0)
if ch == ord('f'):
global cur_func_name
if PY3:
cur_func_name = next(dist_func_names)
else:
cur_func_name = dist_func_names.next()
if ch == 27:
break
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+88
View File
@@ -0,0 +1,88 @@
#!/usr/bin/env python
'''
Floodfill sample.
Usage:
floodfill.py [<image>]
Click on the image to set seed point
Keys:
f - toggle floating range
c - toggle 4/8 connectivity
ESC - exit
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
import sys
class App():
def update(self, dummy=None):
if self.seed_pt is None:
cv.imshow('floodfill', self.img)
return
flooded = self.img.copy()
self.mask[:] = 0
lo = cv.getTrackbarPos('lo', 'floodfill')
hi = cv.getTrackbarPos('hi', 'floodfill')
flags = self.connectivity
if self.fixed_range:
flags |= cv.FLOODFILL_FIXED_RANGE
cv.floodFill(flooded, self.mask, self.seed_pt, (255, 255, 255), (lo,)*3, (hi,)*3, flags)
cv.circle(flooded, self.seed_pt, 2, (0, 0, 255), -1)
cv.imshow('floodfill', flooded)
def onmouse(self, event, x, y, flags, param):
if flags & cv.EVENT_FLAG_LBUTTON:
self.seed_pt = x, y
self.update()
def run(self):
try:
fn = sys.argv[1]
except:
fn = 'fruits.jpg'
self.img = cv.imread(cv.samples.findFile(fn))
if self.img is None:
print('Failed to load image file:', fn)
sys.exit(1)
h, w = self.img.shape[:2]
self.mask = np.zeros((h+2, w+2), np.uint8)
self.seed_pt = None
self.fixed_range = True
self.connectivity = 4
self.update()
cv.setMouseCallback('floodfill', self.onmouse)
cv.createTrackbar('lo', 'floodfill', 20, 255, self.update)
cv.createTrackbar('hi', 'floodfill', 20, 255, self.update)
while True:
ch = cv.waitKey()
if ch == 27:
break
if ch == ord('f'):
self.fixed_range = not self.fixed_range
print('using %s range' % ('floating', 'fixed')[self.fixed_range])
self.update()
if ch == ord('c'):
self.connectivity = 12-self.connectivity
print('connectivity =', self.connectivity)
self.update()
print('Done')
if __name__ == '__main__':
print(__doc__)
App().run()
cv.destroyAllWindows()
+82
View File
@@ -0,0 +1,82 @@
#!/usr/bin/env python
'''
gabor_threads.py
=========
Sample demonstrates:
- use of multiple Gabor filter convolutions to get Fractalius-like image effect (http://www.redfieldplugins.com/filterFractalius.htm)
- use of python threading to accelerate the computation
Usage
-----
gabor_threads.py [image filename]
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
from multiprocessing.pool import ThreadPool
def build_filters():
filters = []
ksize = 31
for theta in np.arange(0, np.pi, np.pi / 16):
kern = cv.getGaborKernel((ksize, ksize), 4.0, theta, 10.0, 0.5, 0, ktype=cv.CV_32F)
kern /= 1.5*kern.sum()
filters.append(kern)
return filters
def process(img, filters):
accum = np.zeros_like(img)
for kern in filters:
fimg = cv.filter2D(img, cv.CV_8UC3, kern)
np.maximum(accum, fimg, accum)
return accum
def process_threaded(img, filters, threadn = 8):
accum = np.zeros_like(img)
def f(kern):
return cv.filter2D(img, cv.CV_8UC3, kern)
pool = ThreadPool(processes=threadn)
for fimg in pool.imap_unordered(f, filters):
np.maximum(accum, fimg, accum)
return accum
def main():
import sys
from common import Timer
try:
img_fn = sys.argv[1]
except:
img_fn = 'baboon.jpg'
img = cv.imread(cv.samples.findFile(img_fn))
if img is None:
print('Failed to load image file:', img_fn)
sys.exit(1)
filters = build_filters()
with Timer('running single-threaded'):
res1 = process(img, filters)
with Timer('running multi-threaded'):
res2 = process_threaded(img, filters)
print('res1 == res2: ', (res1 == res2).all())
cv.imshow('img', img)
cv.imshow('result', res2)
cv.waitKey()
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+77
View File
@@ -0,0 +1,77 @@
#!/usr/bin/env python
# Python 2/3 compatibility
from __future__ import print_function
import sys
PY3 = sys.version_info[0] == 3
if PY3:
xrange = range
import numpy as np
import cv2 as cv
from numpy import random
def make_gaussians(cluster_n, img_size):
points = []
ref_distrs = []
for _i in xrange(cluster_n):
mean = (0.1 + 0.8*random.rand(2)) * img_size
a = (random.rand(2, 2)-0.5)*img_size*0.1
cov = np.dot(a.T, a) + img_size*0.05*np.eye(2)
n = 100 + random.randint(900)
pts = random.multivariate_normal(mean, cov, n)
points.append( pts )
ref_distrs.append( (mean, cov) )
points = np.float32( np.vstack(points) )
return points, ref_distrs
def draw_gaussain(img, mean, cov, color):
x, y = mean
w, u, _vt = cv.SVDecomp(cov)
ang = np.arctan2(u[1, 0], u[0, 0])*(180/np.pi)
s1, s2 = np.sqrt(w)*3.0
cv.ellipse(img, (int(x), int(y)), (int(s1), int(s2)), ang, 0, 360, color, 1, cv.LINE_AA)
def main():
cluster_n = 5
img_size = 512
print('press any key to update distributions, ESC - exit\n')
while True:
print('sampling distributions...')
points, ref_distrs = make_gaussians(cluster_n, img_size)
print('EM (opencv) ...')
em = cv.ml.EM_create()
em.setClustersNumber(cluster_n)
em.setCovarianceMatrixType(cv.ml.EM_COV_MAT_GENERIC)
em.trainEM(points)
means = em.getMeans()
covs = em.getCovs() # Known bug: https://github.com/opencv/opencv/pull/4232
found_distrs = zip(means, covs)
print('ready!\n')
img = np.zeros((img_size, img_size, 3), np.uint8)
for x, y in np.int32(points):
cv.circle(img, (x, y), 1, (255, 255, 255), -1)
for m, cov in ref_distrs:
draw_gaussain(img, m, cov, (0, 255, 0))
for m, cov in found_distrs:
draw_gaussain(img, m, cov, (0, 0, 255))
cv.imshow('gaussian mixture', img)
ch = cv.waitKey(0)
if ch == 27:
break
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+183
View File
@@ -0,0 +1,183 @@
#!/usr/bin/env python
'''
===============================================================================
Interactive Image Segmentation using GrabCut algorithm.
This sample shows interactive image segmentation using grabcut algorithm.
USAGE:
python grabcut.py <filename>
README FIRST:
Two windows will show up, one for input and one for output.
At first, in input window, draw a rectangle around the object using the
right mouse button. Then press 'n' to segment the object (once or a few times)
For any finer touch-ups, you can press any of the keys below and draw lines on
the areas you want. Then again press 'n' to update the output.
Key '0' - To select areas of sure background
Key '1' - To select areas of sure foreground
Key '2' - To select areas of probable background
Key '3' - To select areas of probable foreground
Key 'n' - To update the segmentation
Key 'r' - To reset the setup
Key 's' - To save the results
===============================================================================
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
import sys
class App():
BLUE = [255,0,0] # rectangle color
RED = [0,0,255] # PR BG
GREEN = [0,255,0] # PR FG
BLACK = [0,0,0] # sure BG
WHITE = [255,255,255] # sure FG
DRAW_BG = {'color' : BLACK, 'val' : 0}
DRAW_FG = {'color' : WHITE, 'val' : 1}
DRAW_PR_BG = {'color' : RED, 'val' : 2}
DRAW_PR_FG = {'color' : GREEN, 'val' : 3}
# setting up flags
rect = (0,0,1,1)
drawing = False # flag for drawing curves
rectangle = False # flag for drawing rect
rect_over = False # flag to check if rect drawn
rect_or_mask = 100 # flag for selecting rect or mask mode
value = DRAW_FG # drawing initialized to FG
thickness = 3 # brush thickness
def onmouse(self, event, x, y, flags, param):
# Draw Rectangle
if event == cv.EVENT_RBUTTONDOWN:
self.rectangle = True
self.ix, self.iy = x,y
elif event == cv.EVENT_MOUSEMOVE:
if self.rectangle == True:
self.img = self.img2.copy()
cv.rectangle(self.img, (self.ix, self.iy), (x, y), self.BLUE, 2)
self.rect = (min(self.ix, x), min(self.iy, y), abs(self.ix - x), abs(self.iy - y))
self.rect_or_mask = 0
elif event == cv.EVENT_RBUTTONUP:
self.rectangle = False
self.rect_over = True
cv.rectangle(self.img, (self.ix, self.iy), (x, y), self.BLUE, 2)
self.rect = (min(self.ix, x), min(self.iy, y), abs(self.ix - x), abs(self.iy - y))
self.rect_or_mask = 0
print(" Now press the key 'n' a few times until no further change \n")
# draw touchup curves
if event == cv.EVENT_LBUTTONDOWN:
if self.rect_over == False:
print("first draw rectangle \n")
else:
self.drawing = True
cv.circle(self.img, (x,y), self.thickness, self.value['color'], -1)
cv.circle(self.mask, (x,y), self.thickness, self.value['val'], -1)
elif event == cv.EVENT_MOUSEMOVE:
if self.drawing == True:
cv.circle(self.img, (x, y), self.thickness, self.value['color'], -1)
cv.circle(self.mask, (x, y), self.thickness, self.value['val'], -1)
elif event == cv.EVENT_LBUTTONUP:
if self.drawing == True:
self.drawing = False
cv.circle(self.img, (x, y), self.thickness, self.value['color'], -1)
cv.circle(self.mask, (x, y), self.thickness, self.value['val'], -1)
def run(self):
# Loading images
if len(sys.argv) == 2:
filename = sys.argv[1] # for drawing purposes
else:
print("No input image given, so loading default image, lena.jpg \n")
print("Correct Usage: python grabcut.py <filename> \n")
filename = 'lena.jpg'
self.img = cv.imread(cv.samples.findFile(filename))
self.img2 = self.img.copy() # a copy of original image
self.mask = np.zeros(self.img.shape[:2], dtype = np.uint8) # mask initialized to PR_BG
self.output = np.zeros(self.img.shape, np.uint8) # output image to be shown
# input and output windows
cv.namedWindow('output')
cv.namedWindow('input')
cv.setMouseCallback('input', self.onmouse)
cv.moveWindow('input', self.img.shape[1]+10,90)
print(" Instructions: \n")
print(" Draw a rectangle around the object using right mouse button \n")
while(1):
cv.imshow('output', self.output)
cv.imshow('input', self.img)
k = cv.waitKey(1)
# key bindings
if k == 27: # esc to exit
break
elif k == ord('0'): # BG drawing
print(" mark background regions with left mouse button \n")
self.value = self.DRAW_BG
elif k == ord('1'): # FG drawing
print(" mark foreground regions with left mouse button \n")
self.value = self.DRAW_FG
elif k == ord('2'): # PR_BG drawing
self.value = self.DRAW_PR_BG
elif k == ord('3'): # PR_FG drawing
self.value = self.DRAW_PR_FG
elif k == ord('s'): # save image
bar = np.zeros((self.img.shape[0], 5, 3), np.uint8)
res = np.hstack((self.img2, bar, self.img, bar, self.output))
cv.imwrite('grabcut_output.png', res)
print(" Result saved as image \n")
elif k == ord('r'): # reset everything
print("resetting \n")
self.rect = (0,0,1,1)
self.drawing = False
self.rectangle = False
self.rect_or_mask = 100
self.rect_over = False
self.value = self.DRAW_FG
self.img = self.img2.copy()
self.mask = np.zeros(self.img.shape[:2], dtype = np.uint8) # mask initialized to PR_BG
self.output = np.zeros(self.img.shape, np.uint8) # output image to be shown
elif k == ord('n'): # segment the image
print(""" For finer touchups, mark foreground and background after pressing keys 0-3
and again press 'n' \n""")
try:
bgdmodel = np.zeros((1, 65), np.float64)
fgdmodel = np.zeros((1, 65), np.float64)
if (self.rect_or_mask == 0): # grabcut with rect
cv.grabCut(self.img2, self.mask, self.rect, bgdmodel, fgdmodel, 1, cv.GC_INIT_WITH_RECT)
self.rect_or_mask = 1
elif (self.rect_or_mask == 1): # grabcut with mask
cv.grabCut(self.img2, self.mask, self.rect, bgdmodel, fgdmodel, 1, cv.GC_INIT_WITH_MASK)
except:
import traceback
traceback.print_exc()
mask2 = np.where((self.mask==1) + (self.mask==3), 255, 0).astype('uint8')
self.output = cv.bitwise_and(self.img2, self.img2, mask=mask2)
print('Done')
if __name__ == '__main__':
print(__doc__)
App().run()
cv.destroyAllWindows()
+125
View File
@@ -0,0 +1,125 @@
#!/usr/bin/env python
''' This is a sample for histogram plotting for RGB images and grayscale images for better understanding of colour distribution
Benefit : Learn how to draw histogram of images
Get familier with cv.calcHist, cv.equalizeHist,cv.normalize and some drawing functions
Level : Beginner or Intermediate
Functions : 1) hist_curve : returns histogram of an image drawn as curves
2) hist_lines : return histogram of an image drawn as bins ( only for grayscale images )
Usage : python hist.py <image_file>
Abid Rahman 3/14/12 debug Gary Bradski
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
bins = np.arange(256).reshape(256,1)
def hist_curve(im):
h = np.zeros((300,256,3))
if len(im.shape) == 2:
color = [(255,255,255)]
elif im.shape[2] == 3:
color = [ (255,0,0),(0,255,0),(0,0,255) ]
for ch, col in enumerate(color):
hist_item = cv.calcHist([im],[ch],None,[256],[0,256])
cv.normalize(hist_item,hist_item,0,255,cv.NORM_MINMAX)
hist=np.int32(np.around(hist_item))
pts = np.int32(np.column_stack((bins,hist)))
cv.polylines(h,[pts],False,col)
y=np.flipud(h)
return y
def hist_lines(im):
h = np.zeros((300,256,3))
if len(im.shape)!=2:
print("hist_lines applicable only for grayscale images")
#print("so converting image to grayscale for representation"
im = cv.cvtColor(im,cv.COLOR_BGR2GRAY)
hist_item = cv.calcHist([im],[0],None,[256],[0,256])
cv.normalize(hist_item,hist_item,0,255,cv.NORM_MINMAX)
hist = np.int32(np.around(hist_item))
for x,y in enumerate(hist):
cv.line(h,(x,0),(x,y[0]),(255,255,255))
y = np.flipud(h)
return y
def main():
import sys
if len(sys.argv)>1:
fname = sys.argv[1]
else :
fname = 'lena.jpg'
print("usage : python hist.py <image_file>")
im = cv.imread(cv.samples.findFile(fname))
if im is None:
print('Failed to load image file:', fname)
sys.exit(1)
gray = cv.cvtColor(im,cv.COLOR_BGR2GRAY)
print(''' Histogram plotting \n
Keymap :\n
a - show histogram for color image in curve mode \n
b - show histogram in bin mode \n
c - show equalized histogram (always in bin mode) \n
d - show histogram for gray image in curve mode \n
e - show histogram for a normalized image in curve mode \n
Esc - exit \n
''')
cv.imshow('image',im)
while True:
k = cv.waitKey(0)
if k == ord('a'):
curve = hist_curve(im)
cv.imshow('histogram',curve)
cv.imshow('image',im)
print('a')
elif k == ord('b'):
print('b')
lines = hist_lines(im)
cv.imshow('histogram',lines)
cv.imshow('image',gray)
elif k == ord('c'):
print('c')
equ = cv.equalizeHist(gray)
lines = hist_lines(equ)
cv.imshow('histogram',lines)
cv.imshow('image',equ)
elif k == ord('d'):
print('d')
curve = hist_curve(gray)
cv.imshow('histogram',curve)
cv.imshow('image',gray)
elif k == ord('e'):
print('e')
norm = cv.normalize(gray, gray, alpha = 0,beta = 255,norm_type = cv.NORM_MINMAX)
lines = hist_lines(norm)
cv.imshow('histogram',lines)
cv.imshow('image',norm)
elif k == 27:
print('ESC')
cv.destroyAllWindows()
break
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+49
View File
@@ -0,0 +1,49 @@
#!/usr/bin/python
'''
This example illustrates how to use cv.HoughCircles() function.
Usage:
houghcircles.py [<image_name>]
image argument defaults to board.jpg
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
import sys
def main():
try:
fn = sys.argv[1]
except IndexError:
fn = 'board.jpg'
src = cv.imread(cv.samples.findFile(fn))
img = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
img = cv.medianBlur(img, 5)
cimg = src.copy() # numpy function
circles = cv.HoughCircles(img, cv.HOUGH_GRADIENT, 1, 10, np.array([]), 200, 30, 5, 30)
if circles is not None: # Check if circles have been found and only then iterate over these and add them to the image
circles = np.uint16(np.around(circles))
_a, b, _c = circles.shape
for i in range(b):
cv.circle(cimg, (circles[0][i][0], circles[0][i][1]), circles[0][i][2], (0, 0, 255), 3, cv.LINE_AA)
cv.circle(cimg, (circles[0][i][0], circles[0][i][1]), 2, (0, 255, 0), 3, cv.LINE_AA) # draw center of circle
cv.imshow("detected circles", cimg)
cv.imshow("source", src)
cv.waitKey(0)
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+60
View File
@@ -0,0 +1,60 @@
#!/usr/bin/python
'''
This example illustrates how to use Hough Transform to find lines
Usage:
houghlines.py [<image_name>]
image argument defaults to pic1.png
'''
# Python 2/3 compatibility
from __future__ import print_function
import cv2 as cv
import numpy as np
import sys
import math
def main():
try:
fn = sys.argv[1]
except IndexError:
fn = 'pic1.png'
src = cv.imread(cv.samples.findFile(fn))
dst = cv.Canny(src, 50, 200)
cdst = cv.cvtColor(dst, cv.COLOR_GRAY2BGR)
if True: # HoughLinesP
lines = cv.HoughLinesP(dst, 1, math.pi/180.0, 40, np.array([]), 50, 10)
a, b, _c = lines.shape
for i in range(a):
cv.line(cdst, (lines[i][0][0], lines[i][0][1]), (lines[i][0][2], lines[i][0][3]), (0, 0, 255), 3, cv.LINE_AA)
else: # HoughLines
lines = cv.HoughLines(dst, 1, math.pi/180.0, 50, np.array([]), 0, 0)
if lines is not None:
a, b, _c = lines.shape
for i in range(a):
rho = lines[i][0][0]
theta = lines[i][0][1]
a = math.cos(theta)
b = math.sin(theta)
x0, y0 = a*rho, b*rho
pt1 = ( int(x0+1000*(-b)), int(y0+1000*(a)) )
pt2 = ( int(x0-1000*(-b)), int(y0-1000*(a)) )
cv.line(cdst, pt1, pt2, (0, 0, 255), 3, cv.LINE_AA)
cv.imshow("detected lines", cdst)
cv.imshow("source", src)
cv.waitKey(0)
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+60
View File
@@ -0,0 +1,60 @@
#!/usr/bin/env python
'''
Inpainting sample.
Inpainting repairs damage to images by floodfilling
the damage with surrounding image areas.
Usage:
inpaint.py [<image>]
Keys:
SPACE - inpaint
r - reset the inpainting mask
ESC - exit
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
from common import Sketcher
def main():
import sys
try:
fn = sys.argv[1]
except:
fn = 'fruits.jpg'
img = cv.imread(cv.samples.findFile(fn))
if img is None:
print('Failed to load image file:', fn)
sys.exit(1)
img_mark = img.copy()
mark = np.zeros(img.shape[:2], np.uint8)
sketch = Sketcher('img', [img_mark, mark], lambda : ((255, 255, 255), 255))
while True:
ch = cv.waitKey()
if ch == 27:
break
if ch == ord(' '):
res = cv.inpaint(img_mark, mark, 3, cv.INPAINT_TELEA)
cv.imshow('inpaint', res)
if ch == ord('r'):
img_mark[:] = img
mark[:] = 0
sketch.show()
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+104
View File
@@ -0,0 +1,104 @@
#!/usr/bin/env python
"""
Tracking of rotating point.
Point moves in a circle and is characterized by a 1D state.
state_k+1 = state_k + speed + process_noise N(0, 1e-5)
The speed is constant.
Both state and measurements vectors are 1D (a point angle),
Measurement is the real state + gaussian noise N(0, 1e-1).
The real and the measured points are connected with red line segment,
the real and the estimated points are connected with yellow line segment,
the real and the corrected estimated points are connected with green line segment.
(if Kalman filter works correctly,
the yellow segment should be shorter than the red one and
the green segment should be shorter than the yellow one).
Pressing any key (except ESC) will reset the tracking.
Pressing ESC will stop the program.
"""
# Python 2/3 compatibility
import sys
PY3 = sys.version_info[0] == 3
if PY3:
long = int
import numpy as np
import cv2 as cv
from math import cos, sin, sqrt, pi
def main():
img_height = 500
img_width = 500
kalman = cv.KalmanFilter(2, 1, 0)
code = long(-1)
num_circle_steps = 12
while True:
img = np.zeros((img_height, img_width, 3), np.uint8)
state = np.array([[0.0],[(2 * pi) / num_circle_steps]]) # start state
kalman.transitionMatrix = np.array([[1., 1.], [0., 1.]]) # F. input
kalman.measurementMatrix = 1. * np.eye(1, 2) # H. input
kalman.processNoiseCov = 1e-5 * np.eye(2) # Q. input
kalman.measurementNoiseCov = 1e-1 * np.ones((1, 1)) # R. input
kalman.errorCovPost = 1. * np.eye(2, 2) # P._k|k KF state var
kalman.statePost = 0.1 * np.random.randn(2, 1) # x^_k|k KF state var
while True:
def calc_point(angle):
return (np.around(img_width / 2. + img_width / 3.0 * cos(angle), 0).astype(int),
np.around(img_height / 2. - img_width / 3.0 * sin(angle), 1).astype(int))
img = img * 1e-3
state_angle = state[0, 0]
state_pt = calc_point(state_angle)
# advance Kalman filter to next timestep
# updates statePre, statePost, errorCovPre, errorCovPost
# k-> k+1, x'(k) = A*x(k)
# P'(k) = temp1*At + Q
prediction = kalman.predict()
predict_pt = calc_point(prediction[0, 0]) # equivalent to calc_point(kalman.statePre[0,0])
# generate measurement
measurement = kalman.measurementNoiseCov * np.random.randn(1, 1)
measurement = np.dot(kalman.measurementMatrix, state) + measurement
measurement_angle = measurement[0, 0]
measurement_pt = calc_point(measurement_angle)
# correct the state estimates based on measurements
# updates statePost & errorCovPost
kalman.correct(measurement)
improved_pt = calc_point(kalman.statePost[0, 0])
# plot points
cv.drawMarker(img, measurement_pt, (0, 0, 255), cv.MARKER_SQUARE, 5, 2)
cv.drawMarker(img, predict_pt, (0, 255, 255), cv.MARKER_SQUARE, 5, 2)
cv.drawMarker(img, improved_pt, (0, 255, 0), cv.MARKER_SQUARE, 5, 2)
cv.drawMarker(img, state_pt, (255, 255, 255), cv.MARKER_STAR, 10, 1)
# forecast one step
cv.drawMarker(img, calc_point(np.dot(kalman.transitionMatrix, kalman.statePost)[0, 0]),
(255, 255, 0), cv.MARKER_SQUARE, 12, 1)
cv.line(img, state_pt, measurement_pt, (0, 0, 255), 1, cv.LINE_AA, 0) # red measurement error
cv.line(img, state_pt, predict_pt, (0, 255, 255), 1, cv.LINE_AA, 0) # yellow pre-meas error
cv.line(img, state_pt, improved_pt, (0, 255, 0), 1, cv.LINE_AA, 0) # green post-meas error
# update the real process
process_noise = sqrt(kalman.processNoiseCov[0, 0]) * np.random.randn(2, 1)
state = np.dot(kalman.transitionMatrix, state) + process_noise # x_k+1 = F x_k + w_k
cv.imshow("Kalman", img)
code = cv.waitKey(1000)
if code != -1:
break
if code in [27, ord('q'), ord('Q')]:
break
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+55
View File
@@ -0,0 +1,55 @@
#!/usr/bin/env python
'''
K-means clusterization sample.
Usage:
kmeans.py
Keyboard shortcuts:
ESC - exit
space - generate new distribution
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
from gaussian_mix import make_gaussians
def main():
cluster_n = 5
img_size = 512
# generating bright palette
colors = np.zeros((1, cluster_n, 3), np.uint8)
colors[0,:] = 255
colors[0,:,0] = np.arange(0, 180, 180.0/cluster_n)
colors = cv.cvtColor(colors, cv.COLOR_HSV2BGR)[0]
while True:
print('sampling distributions...')
points, _ = make_gaussians(cluster_n, img_size)
term_crit = (cv.TERM_CRITERIA_EPS, 30, 0.1)
_ret, labels, _centers = cv.kmeans(points, cluster_n, None, term_crit, 10, 0)
img = np.zeros((img_size, img_size, 3), np.uint8)
for (x, y), label in zip(np.int32(points), labels.ravel()):
c = list(map(int, colors[label]))
cv.circle(img, (x, y), 1, c, -1)
cv.imshow('kmeans', img)
ch = cv.waitKey(0)
if ch == 27:
break
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+69
View File
@@ -0,0 +1,69 @@
#!/usr/bin/env python
'''
This program demonstrates Laplace point/edge detection using
OpenCV function Laplacian()
It captures from the camera of your choice: 0, 1, ... default 0
Usage:
python laplace.py <ddepth> <smoothType> <sigma>
If no arguments given default arguments will be used.
Keyboard Shortcuts:
Press space bar to exit the program.
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
import sys
def main():
# Declare the variables we are going to use
ddepth = cv.CV_16S
smoothType = "MedianBlur"
sigma = 3
if len(sys.argv)==4:
ddepth = sys.argv[1]
smoothType = sys.argv[2]
sigma = sys.argv[3]
# Taking input from the camera
cap=cv.VideoCapture(0)
# Create Window and Trackbar
cv.namedWindow("Laplace of Image", cv.WINDOW_AUTOSIZE)
cv.createTrackbar("Kernel Size Bar", "Laplace of Image", sigma, 15, lambda x:x)
# Printing frame width, height and FPS
print("=="*40)
print("Frame Width: ", cap.get(cv.CAP_PROP_FRAME_WIDTH), "Frame Height: ", cap.get(cv.CAP_PROP_FRAME_HEIGHT), "FPS: ", cap.get(cv.CAP_PROP_FPS))
while True:
# Reading input from the camera
ret, frame = cap.read()
if ret == False:
print("Can't open camera/video stream")
break
# Taking input/position from the trackbar
sigma = cv.getTrackbarPos("Kernel Size Bar", "Laplace of Image")
# Setting kernel size
ksize = (sigma*5)|1
# Removing noise by blurring with a filter
if smoothType == "GAUSSIAN":
smoothed = cv.GaussianBlur(frame, (ksize, ksize), sigma, sigma)
if smoothType == "BLUR":
smoothed = cv.blur(frame, (ksize, ksize))
if smoothType == "MedianBlur":
smoothed = cv.medianBlur(frame, ksize)
# Apply Laplace function
laplace = cv.Laplacian(smoothed, ddepth, 5)
# Converting back to uint8
result = cv.convertScaleAbs(laplace, (sigma+1)*0.25)
# Display Output
cv.imshow("Laplace of Image", result)
k = cv.waitKey(30)
if k == 27:
return
if __name__ == "__main__":
print(__doc__)
main()
cv.destroyAllWindows()
+82
View File
@@ -0,0 +1,82 @@
#!/usr/bin/env python
''' An example of Laplacian Pyramid construction and merging.
Level : Intermediate
Usage : python lappyr.py [<video source>]
References:
http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.54.299
Alexander Mordvintsev 6/10/12
'''
# Python 2/3 compatibility
from __future__ import print_function
import sys
PY3 = sys.version_info[0] == 3
if PY3:
xrange = range
import numpy as np
import cv2 as cv
import video
from common import nothing, getsize
def build_lappyr(img, leveln=6, dtype=np.int16):
img = dtype(img)
levels = []
for _i in xrange(leveln-1):
next_img = cv.pyrDown(img)
img1 = cv.pyrUp(next_img, dstsize=getsize(img))
levels.append(img-img1)
img = next_img
levels.append(img)
return levels
def merge_lappyr(levels):
img = levels[-1]
for lev_img in levels[-2::-1]:
img = cv.pyrUp(img, dstsize=getsize(lev_img))
img += lev_img
return np.uint8(np.clip(img, 0, 255))
def main():
import sys
try:
fn = sys.argv[1]
except:
fn = 0
cap = video.create_capture(fn)
leveln = 6
cv.namedWindow('level control')
for i in xrange(leveln):
cv.createTrackbar('%d'%i, 'level control', 5, 50, nothing)
while True:
_ret, frame = cap.read()
pyr = build_lappyr(frame, leveln)
for i in xrange(leveln):
v = int(cv.getTrackbarPos('%d'%i, 'level control') / 5)
pyr[i] *= v
res = merge_lappyr(pyr)
cv.imshow('laplacian pyramid filter', res)
if cv.waitKey(1) == 27:
break
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+194
View File
@@ -0,0 +1,194 @@
#!/usr/bin/env python
'''
The sample demonstrates how to train Random Trees classifier
(or Boosting classifier, or MLP, or Knearest, or Support Vector Machines) using the provided dataset.
We use the sample database letter-recognition.data
from UCI Repository, here is the link:
Newman, D.J. & Hettich, S. & Blake, C.L. & Merz, C.J. (1998).
UCI Repository of machine learning databases
[http://www.ics.uci.edu/~mlearn/MLRepository.html].
Irvine, CA: University of California, Department of Information and Computer Science.
The dataset consists of 20000 feature vectors along with the
responses - capital latin letters A..Z.
The first 10000 samples are used for training
and the remaining 10000 - to test the classifier.
======================================================
USAGE:
letter_recog.py [--model <model>]
[--data <data fn>]
[--load <model fn>] [--save <model fn>]
Models: RTrees, KNearest, Boost, SVM, MLP
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
def load_base(fn):
a = np.loadtxt(fn, np.float32, delimiter=',', converters={ 0 : lambda ch : ord(ch)-ord('A') })
samples, responses = a[:,1:], a[:,0]
return samples, responses
class LetterStatModel(object):
class_n = 26
train_ratio = 0.5
def load(self, fn):
self.model = self.model.load(fn)
def save(self, fn):
self.model.save(fn)
def unroll_samples(self, samples):
sample_n, var_n = samples.shape
new_samples = np.zeros((sample_n * self.class_n, var_n+1), np.float32)
new_samples[:,:-1] = np.repeat(samples, self.class_n, axis=0)
new_samples[:,-1] = np.tile(np.arange(self.class_n), sample_n)
return new_samples
def unroll_responses(self, responses):
sample_n = len(responses)
new_responses = np.zeros(sample_n*self.class_n, np.int32)
resp_idx = np.int32( responses + np.arange(sample_n)*self.class_n )
new_responses[resp_idx] = 1
return new_responses
class RTrees(LetterStatModel):
def __init__(self):
self.model = cv.ml.RTrees_create()
def train(self, samples, responses):
self.model.setMaxDepth(20)
self.model.train(samples, cv.ml.ROW_SAMPLE, responses.astype(int))
def predict(self, samples):
_ret, resp = self.model.predict(samples)
return resp.ravel()
class KNearest(LetterStatModel):
def __init__(self):
self.model = cv.ml.KNearest_create()
def train(self, samples, responses):
self.model.train(samples, cv.ml.ROW_SAMPLE, responses)
def predict(self, samples):
_retval, results, _neigh_resp, _dists = self.model.findNearest(samples, k = 10)
return results.ravel()
class Boost(LetterStatModel):
def __init__(self):
self.model = cv.ml.Boost_create()
def train(self, samples, responses):
_sample_n, var_n = samples.shape
new_samples = self.unroll_samples(samples)
new_responses = self.unroll_responses(responses)
var_types = np.array([cv.ml.VAR_NUMERICAL] * var_n + [cv.ml.VAR_CATEGORICAL, cv.ml.VAR_CATEGORICAL], np.uint8)
self.model.setWeakCount(15)
self.model.setMaxDepth(10)
self.model.train(cv.ml.TrainData_create(new_samples, cv.ml.ROW_SAMPLE, new_responses.astype(int), varType = var_types))
def predict(self, samples):
new_samples = self.unroll_samples(samples)
_ret, resp = self.model.predict(new_samples)
return resp.ravel().reshape(-1, self.class_n).argmax(1)
class SVM(LetterStatModel):
def __init__(self):
self.model = cv.ml.SVM_create()
def train(self, samples, responses):
self.model.setType(cv.ml.SVM_C_SVC)
self.model.setC(1)
self.model.setKernel(cv.ml.SVM_RBF)
self.model.setGamma(.1)
self.model.train(samples, cv.ml.ROW_SAMPLE, responses.astype(int))
def predict(self, samples):
_ret, resp = self.model.predict(samples)
return resp.ravel()
class MLP(LetterStatModel):
def __init__(self):
self.model = cv.ml.ANN_MLP_create()
def train(self, samples, responses):
_sample_n, var_n = samples.shape
new_responses = self.unroll_responses(responses).reshape(-1, self.class_n)
layer_sizes = np.int32([var_n, 100, 100, self.class_n])
self.model.setLayerSizes(layer_sizes)
self.model.setTrainMethod(cv.ml.ANN_MLP_BACKPROP)
self.model.setBackpropMomentumScale(0.0)
self.model.setBackpropWeightScale(0.001)
self.model.setTermCriteria((cv.TERM_CRITERIA_COUNT, 20, 0.01))
self.model.setActivationFunction(cv.ml.ANN_MLP_SIGMOID_SYM, 2, 1)
self.model.train(samples, cv.ml.ROW_SAMPLE, np.float32(new_responses))
def predict(self, samples):
_ret, resp = self.model.predict(samples)
return resp.argmax(-1)
def main():
import getopt
import sys
models = [RTrees, KNearest, Boost, SVM, MLP] # NBayes
models = dict( [(cls.__name__.lower(), cls) for cls in models] )
args, dummy = getopt.getopt(sys.argv[1:], '', ['model=', 'data=', 'load=', 'save='])
args = dict(args)
args.setdefault('--model', 'svm')
args.setdefault('--data', 'letter-recognition.data')
datafile = cv.samples.findFile(args['--data'])
print('loading data %s ...' % datafile)
samples, responses = load_base(datafile)
Model = models[args['--model']]
model = Model()
train_n = int(len(samples)*model.train_ratio)
if '--load' in args:
fn = args['--load']
print('loading model from %s ...' % fn)
model.load(fn)
else:
print('training %s ...' % Model.__name__)
model.train(samples[:train_n], responses[:train_n])
print('testing...')
train_rate = np.mean(model.predict(samples[:train_n]) == responses[:train_n].astype(int))
test_rate = np.mean(model.predict(samples[train_n:]) == responses[train_n:].astype(int))
print('train rate: %f test rate: %f' % (train_rate*100, test_rate*100))
if '--save' in args:
fn = args['--save']
print('saving model to %s ...' % fn)
model.save(fn)
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+123
View File
@@ -0,0 +1,123 @@
#!/usr/bin/env python
'''
Lucas-Kanade homography tracker
===============================
Lucas-Kanade sparse optical flow demo. Uses goodFeaturesToTrack
for track initialization and back-tracking for match verification
between frames. Finds homography between reference and current views.
Usage
-----
lk_homography.py [<video_source>]
Keys
----
ESC - exit
SPACE - start tracking
r - toggle RANSAC
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
import video
from common import draw_str
from video import presets
lk_params = dict( winSize = (19, 19),
maxLevel = 2,
criteria = (cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 0.03))
feature_params = dict( maxCorners = 1000,
qualityLevel = 0.01,
minDistance = 8,
blockSize = 19 )
def checkedTrace(img0, img1, p0, back_threshold = 1.0):
p1, _st, _err = cv.calcOpticalFlowPyrLK(img0, img1, p0, None, **lk_params)
p0r, _st, _err = cv.calcOpticalFlowPyrLK(img1, img0, p1, None, **lk_params)
d = abs(p0-p0r).reshape(-1, 2).max(-1)
status = d < back_threshold
return p1, status
green = (0, 255, 0)
red = (0, 0, 255)
class App:
def __init__(self, video_src):
self.cam = self.cam = video.create_capture(video_src, presets['book'])
self.p0 = None
self.use_ransac = True
def run(self):
while True:
_ret, frame = self.cam.read()
frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
vis = frame.copy()
if self.p0 is not None:
p2, trace_status = checkedTrace(self.gray1, frame_gray, self.p1)
self.p1 = p2[trace_status].copy()
self.p0 = self.p0[trace_status].copy()
self.gray1 = frame_gray
if len(self.p0) < 4:
self.p0 = None
continue
H, status = cv.findHomography(self.p0, self.p1, (0, cv.RANSAC)[self.use_ransac], 10.0)
h, w = frame.shape[:2]
overlay = cv.warpPerspective(self.frame0, H, (w, h))
vis = cv.addWeighted(vis, 0.5, overlay, 0.5, 0.0)
for (x0, y0), (x1, y1), good in zip(self.p0[:,0], self.p1[:,0], status[:,0]):
if good:
cv.line(vis, (int(x0), int(y0)), (int(x1), int(y1)), (0, 128, 0))
cv.circle(vis, (int(x1), int(y1)), 2, (red, green)[good], -1)
draw_str(vis, (20, 20), 'track count: %d' % len(self.p1))
if self.use_ransac:
draw_str(vis, (20, 40), 'RANSAC')
else:
p = cv.goodFeaturesToTrack(frame_gray, **feature_params)
if p is not None:
for x, y in p[:,0]:
cv.circle(vis, (int(x), int(y)), 2, green, -1)
draw_str(vis, (20, 20), 'feature count: %d' % len(p))
cv.imshow('lk_homography', vis)
ch = cv.waitKey(1)
if ch == 27:
break
if ch == ord(' '):
self.frame0 = frame.copy()
self.p0 = cv.goodFeaturesToTrack(frame_gray, **feature_params)
if self.p0 is not None:
self.p1 = self.p0
self.gray0 = frame_gray
self.gray1 = frame_gray
if ch == ord('r'):
self.use_ransac = not self.use_ransac
def main():
import sys
try:
video_src = sys.argv[1]
except:
video_src = 0
App(video_src).run()
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+106
View File
@@ -0,0 +1,106 @@
#!/usr/bin/env python
'''
Lucas-Kanade tracker
====================
Lucas-Kanade sparse optical flow demo. Uses goodFeaturesToTrack
for track initialization and back-tracking for match verification
between frames.
Usage
-----
lk_track.py [<video_source>]
Keys
----
ESC - exit
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
import video
from common import anorm2, draw_str
lk_params = dict( winSize = (15, 15),
maxLevel = 2,
criteria = (cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 0.03))
feature_params = dict( maxCorners = 500,
qualityLevel = 0.3,
minDistance = 7,
blockSize = 7 )
class App:
def __init__(self, video_src):
self.track_len = 10
self.detect_interval = 5
self.tracks = []
self.cam = video.create_capture(video_src)
self.frame_idx = 0
def run(self):
while True:
_ret, frame = self.cam.read()
frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
vis = frame.copy()
if len(self.tracks) > 0:
img0, img1 = self.prev_gray, frame_gray
p0 = np.float32([tr[-1] for tr in self.tracks]).reshape(-1, 1, 2)
p1, _st, _err = cv.calcOpticalFlowPyrLK(img0, img1, p0, None, **lk_params)
p0r, _st, _err = cv.calcOpticalFlowPyrLK(img1, img0, p1, None, **lk_params)
d = abs(p0-p0r).reshape(-1, 2).max(-1)
good = d < 1
new_tracks = []
for tr, (x, y), good_flag in zip(self.tracks, p1.reshape(-1, 2), good):
if not good_flag:
continue
tr.append((x, y))
if len(tr) > self.track_len:
del tr[0]
new_tracks.append(tr)
cv.circle(vis, (int(x), int(y)), 2, (0, 255, 0), -1)
self.tracks = new_tracks
cv.polylines(vis, [np.int32(tr) for tr in self.tracks], False, (0, 255, 0))
draw_str(vis, (20, 20), 'track count: %d' % len(self.tracks))
if self.frame_idx % self.detect_interval == 0:
mask = np.zeros_like(frame_gray)
mask[:] = 255
for x, y in [np.int32(tr[-1]) for tr in self.tracks]:
cv.circle(mask, (x, y), 5, 0, -1)
p = cv.goodFeaturesToTrack(frame_gray, mask = mask, **feature_params)
if p is not None:
for x, y in np.float32(p).reshape(-1, 2):
self.tracks.append([(x, y)])
self.frame_idx += 1
self.prev_gray = frame_gray
cv.imshow('lk_track', vis)
ch = cv.waitKey(1)
if ch == 27:
break
def main():
import sys
try:
video_src = sys.argv[1]
except:
video_src = 0
App(video_src).run()
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+45
View File
@@ -0,0 +1,45 @@
#!/usr/bin/env python
'''
plots image as logPolar and linearPolar
Usage:
logpolar.py
Keys:
ESC - exit
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
def main():
import sys
try:
fn = sys.argv[1]
except IndexError:
fn = 'fruits.jpg'
img = cv.imread(cv.samples.findFile(fn))
if img is None:
print('Failed to load image file:', fn)
sys.exit(1)
img2 = cv.logPolar(img, (img.shape[0]/2, img.shape[1]/2), 40, cv.WARP_FILL_OUTLIERS)
img3 = cv.linearPolar(img, (img.shape[0]/2, img.shape[1]/2), 40, cv.WARP_FILL_OUTLIERS)
cv.imshow('before', img)
cv.imshow('logpolar', img2)
cv.imshow('linearpolar', img3)
cv.waitKey(0)
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+104
View File
@@ -0,0 +1,104 @@
#!/usr/bin/env python
'''
Morphology operations.
Usage:
morphology.py [<image>]
Keys:
1 - change operation
2 - change structure element shape
ESC - exit
'''
# Python 2/3 compatibility
from __future__ import print_function
import sys
PY3 = sys.version_info[0] == 3
import numpy as np
import cv2 as cv
def main():
import sys
from itertools import cycle
from common import draw_str
try:
fn = sys.argv[1]
except:
fn = 'baboon.jpg'
img = cv.imread(cv.samples.findFile(fn))
if img is None:
print('Failed to load image file:', fn)
sys.exit(1)
cv.imshow('original', img)
modes = cycle(['erode/dilate', 'open/close', 'blackhat/tophat', 'gradient'])
str_modes = cycle(['ellipse', 'rect', 'cross', 'diamond'])
if PY3:
cur_mode = next(modes)
cur_str_mode = next(str_modes)
else:
cur_mode = modes.next()
cur_str_mode = str_modes.next()
def update(dummy=None):
try: # do not get trackbar position while trackbar is not created
sz = cv.getTrackbarPos('op/size', 'morphology')
iters = cv.getTrackbarPos('iters', 'morphology')
except:
return
opers = cur_mode.split('/')
if len(opers) > 1:
sz = sz - 10
op = opers[sz > 0]
sz = abs(sz)
else:
op = opers[0]
sz = sz*2+1
str_name = 'MORPH_' + cur_str_mode.upper()
oper_name = 'MORPH_' + op.upper()
st = cv.getStructuringElement(getattr(cv, str_name), (sz, sz))
res = cv.morphologyEx(img, getattr(cv, oper_name), st, iterations=iters)
draw_str(res, (10, 20), 'mode: ' + cur_mode)
draw_str(res, (10, 40), 'operation: ' + oper_name)
draw_str(res, (10, 60), 'structure: ' + str_name)
draw_str(res, (10, 80), 'ksize: %d iters: %d' % (sz, iters))
cv.imshow('morphology', res)
cv.namedWindow('morphology')
cv.createTrackbar('op/size', 'morphology', 12, 20, update)
cv.createTrackbar('iters', 'morphology', 1, 10, update)
update()
while True:
ch = cv.waitKey()
if ch == 27:
break
if ch == ord('1'):
if PY3:
cur_mode = next(modes)
else:
cur_mode = modes.next()
if ch == ord('2'):
if PY3:
cur_str_mode = next(str_modes)
else:
cur_str_mode = str_modes.next()
update()
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+198
View File
@@ -0,0 +1,198 @@
#!/usr/bin/env python
'''
MOSSE tracking sample
This sample implements correlation-based tracking approach, described in [1].
Usage:
mosse.py [--pause] [<video source>]
--pause - Start with playback paused at the first video frame.
Useful for tracking target selection.
Draw rectangles around objects with a mouse to track them.
Keys:
SPACE - pause video
c - clear targets
[1] David S. Bolme et al. "Visual Object Tracking using Adaptive Correlation Filters"
http://www.cs.colostate.edu/~draper/papers/bolme_cvpr10.pdf
'''
# Python 2/3 compatibility
from __future__ import print_function
import sys
PY3 = sys.version_info[0] == 3
if PY3:
xrange = range
import numpy as np
import cv2 as cv
from common import draw_str, RectSelector
import video
def rnd_warp(a):
h, w = a.shape[:2]
T = np.zeros((2, 3))
coef = 0.2
ang = (np.random.rand()-0.5)*coef
c, s = np.cos(ang), np.sin(ang)
T[:2, :2] = [[c,-s], [s, c]]
T[:2, :2] += (np.random.rand(2, 2) - 0.5)*coef
c = (w/2, h/2)
T[:,2] = c - np.dot(T[:2, :2], c)
return cv.warpAffine(a, T, (w, h), borderMode = cv.BORDER_REFLECT)
def divSpec(A, B):
Ar, Ai = A[...,0], A[...,1]
Br, Bi = B[...,0], B[...,1]
C = (Ar+1j*Ai)/(Br+1j*Bi)
C = np.dstack([np.real(C), np.imag(C)]).copy()
return C
eps = 1e-5
class MOSSE:
def __init__(self, frame, rect):
x1, y1, x2, y2 = rect
w, h = map(cv.getOptimalDFTSize, [x2-x1, y2-y1])
x1, y1 = (x1+x2-w)//2, (y1+y2-h)//2
self.pos = x, y = x1+0.5*(w-1), y1+0.5*(h-1)
self.size = w, h
img = cv.getRectSubPix(frame, (w, h), (x, y))
self.win = cv.createHanningWindow((w, h), cv.CV_32F)
g = np.zeros((h, w), np.float32)
g[h//2, w//2] = 1
g = cv.GaussianBlur(g, (-1, -1), 2.0)
g /= g.max()
self.G = cv.dft(g, flags=cv.DFT_COMPLEX_OUTPUT)
self.H1 = np.zeros_like(self.G)
self.H2 = np.zeros_like(self.G)
for _i in xrange(128):
a = self.preprocess(rnd_warp(img))
A = cv.dft(a, flags=cv.DFT_COMPLEX_OUTPUT)
self.H1 += cv.mulSpectrums(self.G, A, 0, conjB=True)
self.H2 += cv.mulSpectrums( A, A, 0, conjB=True)
self.update_kernel()
self.update(frame)
def update(self, frame, rate = 0.125):
(x, y), (w, h) = self.pos, self.size
self.last_img = img = cv.getRectSubPix(frame, (w, h), (x, y))
img = self.preprocess(img)
self.last_resp, (dx, dy), self.psr = self.correlate(img)
self.good = self.psr > 8.0
if not self.good:
return
self.pos = x+dx, y+dy
self.last_img = img = cv.getRectSubPix(frame, (w, h), self.pos)
img = self.preprocess(img)
A = cv.dft(img, flags=cv.DFT_COMPLEX_OUTPUT)
H1 = cv.mulSpectrums(self.G, A, 0, conjB=True)
H2 = cv.mulSpectrums( A, A, 0, conjB=True)
self.H1 = self.H1 * (1.0-rate) + H1 * rate
self.H2 = self.H2 * (1.0-rate) + H2 * rate
self.update_kernel()
@property
def state_vis(self):
f = cv.idft(self.H, flags=cv.DFT_SCALE | cv.DFT_REAL_OUTPUT )
h, w = f.shape
f = np.roll(f, -h//2, 0)
f = np.roll(f, -w//2, 1)
kernel = np.uint8( (f-f.min()) / np.ptp(f)*255 )
resp = self.last_resp
resp = np.uint8(np.clip(resp/resp.max(), 0, 1)*255)
vis = np.hstack([self.last_img, kernel, resp])
return vis
def draw_state(self, vis):
(x, y), (w, h) = self.pos, self.size
x1, y1, x2, y2 = int(x-0.5*w), int(y-0.5*h), int(x+0.5*w), int(y+0.5*h)
cv.rectangle(vis, (x1, y1), (x2, y2), (0, 0, 255))
if self.good:
cv.circle(vis, (int(x), int(y)), 2, (0, 0, 255), -1)
else:
cv.line(vis, (x1, y1), (x2, y2), (0, 0, 255))
cv.line(vis, (x2, y1), (x1, y2), (0, 0, 255))
draw_str(vis, (x1, y2+16), 'PSR: %.2f' % self.psr)
def preprocess(self, img):
img = np.log(np.float32(img)+1.0)
img = (img-img.mean()) / (img.std()+eps)
return img*self.win
def correlate(self, img):
C = cv.mulSpectrums(cv.dft(img, flags=cv.DFT_COMPLEX_OUTPUT), self.H, 0, conjB=True)
resp = cv.idft(C, flags=cv.DFT_SCALE | cv.DFT_REAL_OUTPUT)
h, w = resp.shape
_, mval, _, (mx, my) = cv.minMaxLoc(resp)
side_resp = resp.copy()
cv.rectangle(side_resp, (mx-5, my-5), (mx+5, my+5), 0, -1)
smean, sstd = side_resp.mean(), side_resp.std()
psr = (mval-smean) / (sstd+eps)
return resp, (mx-w//2, my-h//2), psr
def update_kernel(self):
self.H = divSpec(self.H1, self.H2)
self.H[...,1] *= -1
class App:
def __init__(self, video_src, paused = False):
self.cap = video.create_capture(video_src)
_, self.frame = self.cap.read()
cv.imshow('frame', self.frame)
self.rect_sel = RectSelector('frame', self.onrect)
self.trackers = []
self.paused = paused
def onrect(self, rect):
frame_gray = cv.cvtColor(self.frame, cv.COLOR_BGR2GRAY)
tracker = MOSSE(frame_gray, rect)
self.trackers.append(tracker)
def run(self):
while True:
if not self.paused:
ret, self.frame = self.cap.read()
if not ret:
break
frame_gray = cv.cvtColor(self.frame, cv.COLOR_BGR2GRAY)
for tracker in self.trackers:
tracker.update(frame_gray)
vis = self.frame.copy()
for tracker in self.trackers:
tracker.draw_state(vis)
if len(self.trackers) > 0:
cv.imshow('tracker state', self.trackers[-1].state_vis)
self.rect_sel.draw(vis)
cv.imshow('frame', vis)
ch = cv.waitKey(10)
if ch == 27:
break
if ch == ord(' '):
self.paused = not self.paused
if ch == ord('c'):
self.trackers = []
if __name__ == '__main__':
print (__doc__)
import sys, getopt
opts, args = getopt.getopt(sys.argv[1:], '', ['pause'])
opts = dict(opts)
try:
video_src = args[0]
except:
video_src = '0'
App(video_src, paused = '--pause' in opts).run()
+88
View File
@@ -0,0 +1,88 @@
#!/usr/bin/env python
'''
mouse_and_match.py [-i path | --input path: default ../data/]
Demonstrate using a mouse to interact with an image:
Read in the images in a directory one by one
Allow the user to select parts of an image with a mouse
When they let go of the mouse, it correlates (using matchTemplate) that patch with the image.
SPACE for next image
ESC to exit
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
# built-in modules
import os
import sys
import glob
import argparse
from math import *
class App():
drag_start = None
sel = (0,0,0,0)
def onmouse(self, event, x, y, flags, param):
if event == cv.EVENT_LBUTTONDOWN:
self.drag_start = x, y
self.sel = (0,0,0,0)
elif event == cv.EVENT_LBUTTONUP:
if self.sel[2] > self.sel[0] and self.sel[3] > self.sel[1]:
patch = self.gray[self.sel[1]:self.sel[3], self.sel[0]:self.sel[2]]
result = cv.matchTemplate(self.gray, patch, cv.TM_CCOEFF_NORMED)
result = np.abs(result)**3
_val, result = cv.threshold(result, 0.01, 0, cv.THRESH_TOZERO)
result8 = cv.normalize(result, None, 0, 255, cv.NORM_MINMAX, cv.CV_8U)
cv.imshow("result", result8)
self.drag_start = None
elif self.drag_start:
#print flags
if flags & cv.EVENT_FLAG_LBUTTON:
minpos = min(self.drag_start[0], x), min(self.drag_start[1], y)
maxpos = max(self.drag_start[0], x), max(self.drag_start[1], y)
self.sel = (minpos[0], minpos[1], maxpos[0], maxpos[1])
img = cv.cvtColor(self.gray, cv.COLOR_GRAY2BGR)
cv.rectangle(img, (self.sel[0], self.sel[1]), (self.sel[2], self.sel[3]), (0,255,255), 1)
cv.imshow("gray", img)
else:
print("selection is complete")
self.drag_start = None
def run(self):
parser = argparse.ArgumentParser(description='Demonstrate mouse interaction with images')
parser.add_argument("-i","--input", default='../data/', help="Input directory.")
args = parser.parse_args()
path = args.input
cv.namedWindow("gray",1)
cv.setMouseCallback("gray", self.onmouse)
'''Loop through all the images in the directory'''
for infile in glob.glob( os.path.join(path, '*.*') ):
ext = os.path.splitext(infile)[1][1:] #get the filename extension
if ext == "png" or ext == "jpg" or ext == "bmp" or ext == "tiff" or ext == "pbm":
print(infile)
img = cv.imread(infile, cv.IMREAD_COLOR)
if img is None:
continue
self.sel = (0,0,0,0)
self.drag_start = None
self.gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
cv.imshow("gray", self.gray)
if cv.waitKey() == 27:
break
print('Done')
if __name__ == '__main__':
print(__doc__)
App().run()
cv.destroyAllWindows()
+56
View File
@@ -0,0 +1,56 @@
#!/usr/bin/env python
'''
MSER detector demo
==================
Usage:
------
mser.py [<video source>]
Keys:
-----
ESC - exit
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
import video
import sys
def main():
try:
video_src = sys.argv[1]
except:
video_src = 0
cam = video.create_capture(video_src)
mser = cv.MSER_create()
while True:
ret, img = cam.read()
if ret == 0:
break
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
vis = img.copy()
regions, _ = mser.detectRegions(gray)
hulls = [cv.convexHull(p.reshape(-1, 1, 2)) for p in regions]
cv.polylines(vis, hulls, 1, (0, 255, 0))
cv.imshow('img', vis)
if cv.waitKey(5) == 27:
break
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+41
View File
@@ -0,0 +1,41 @@
#!/usr/bin/env python
'''
prints OpenCV version
Usage:
opencv_version.py [<params>]
params:
--build: print complete build info
--help: print this help
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
def main():
import sys
try:
param = sys.argv[1]
except IndexError:
param = ""
if "--build" == param:
print(cv.getBuildInformation())
elif "--help" == param:
print("\t--build\n\t\tprint complete build info")
print("\t--help\n\t\tprint this help")
else:
print("Welcome to OpenCV")
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+104
View File
@@ -0,0 +1,104 @@
#!/usr/bin/env python
'''
example to show optical flow
USAGE: opt_flow.py [<video_source>]
Keys:
1 - toggle HSV flow visualization
2 - toggle glitch
Keys:
ESC - exit
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
import video
def draw_flow(img, flow, step=16):
h, w = img.shape[:2]
y, x = np.mgrid[step/2:h:step, step/2:w:step].reshape(2,-1).astype(int)
fx, fy = flow[y,x].T
lines = np.vstack([x, y, x+fx, y+fy]).T.reshape(-1, 2, 2)
lines = np.int32(lines + 0.5)
vis = cv.cvtColor(img, cv.COLOR_GRAY2BGR)
cv.polylines(vis, lines, 0, (0, 255, 0))
for (x1, y1), (_x2, _y2) in lines:
cv.circle(vis, (x1, y1), 1, (0, 255, 0), -1)
return vis
def draw_hsv(flow):
h, w = flow.shape[:2]
fx, fy = flow[:,:,0], flow[:,:,1]
ang = np.arctan2(fy, fx) + np.pi
v = np.sqrt(fx*fx+fy*fy)
hsv = np.zeros((h, w, 3), np.uint8)
hsv[...,0] = ang*(180/np.pi/2)
hsv[...,1] = 255
hsv[...,2] = np.minimum(v*4, 255)
bgr = cv.cvtColor(hsv, cv.COLOR_HSV2BGR)
return bgr
def warp_flow(img, flow):
h, w = flow.shape[:2]
flow = -flow
flow[:,:,0] += np.arange(w)
flow[:,:,1] += np.arange(h)[:,np.newaxis]
res = cv.remap(img, flow, None, cv.INTER_LINEAR)
return res
def main():
import sys
try:
fn = sys.argv[1]
except IndexError:
fn = 0
cam = video.create_capture(fn)
_ret, prev = cam.read()
prevgray = cv.cvtColor(prev, cv.COLOR_BGR2GRAY)
show_hsv = False
show_glitch = False
cur_glitch = prev.copy()
while True:
_ret, img = cam.read()
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
flow = cv.calcOpticalFlowFarneback(prevgray, gray, None, 0.5, 3, 15, 3, 5, 1.2, 0)
prevgray = gray
cv.imshow('flow', draw_flow(gray, flow))
if show_hsv:
cv.imshow('flow HSV', draw_hsv(flow))
if show_glitch:
cur_glitch = warp_flow(cur_glitch, flow)
cv.imshow('glitch', cur_glitch)
ch = cv.waitKey(5)
if ch == 27:
break
if ch == ord('1'):
show_hsv = not show_hsv
print('HSV flow visualization is', ['off', 'on'][show_hsv])
if ch == ord('2'):
show_glitch = not show_glitch
if show_glitch:
cur_glitch = img.copy()
print('glitch is', ['off', 'on'][show_glitch])
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+76
View File
@@ -0,0 +1,76 @@
#!/usr/bin/env python
'''
example to detect upright people in images using HOG features
Usage:
peopledetect.py <image_names>
Press any key to continue, ESC to stop.
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
def inside(r, q):
rx, ry, rw, rh = r
qx, qy, qw, qh = q
return rx > qx and ry > qy and rx + rw < qx + qw and ry + rh < qy + qh
def draw_detections(img, rects, thickness = 1):
for x, y, w, h in rects:
# the HOG detector returns slightly larger rectangles than the real objects.
# so we slightly shrink the rectangles to get a nicer output.
pad_w, pad_h = int(0.15*w), int(0.05*h)
cv.rectangle(img, (x+pad_w, y+pad_h), (x+w-pad_w, y+h-pad_h), (0, 255, 0), thickness)
def main():
import sys
from glob import glob
import itertools as it
hog = cv.HOGDescriptor()
hog.setSVMDetector( cv.HOGDescriptor_getDefaultPeopleDetector() )
default = [cv.samples.findFile('basketball2.png')] if len(sys.argv[1:]) == 0 else []
for fn in it.chain(*map(glob, default + sys.argv[1:])):
print(fn, ' - ',)
try:
img = cv.imread(fn)
if img is None:
print('Failed to load image file:', fn)
continue
except:
print('loading error')
continue
found, _w = hog.detectMultiScale(img, winStride=(8,8), padding=(32,32), scale=1.05)
found_filtered = []
for ri, r in enumerate(found):
for qi, q in enumerate(found):
if ri != qi and inside(r, q):
break
else:
found_filtered.append(r)
draw_detections(img, found)
draw_detections(img, found_filtered, 3)
print('%d (%d) found' % (len(found_filtered), len(found)))
cv.imshow('img', img)
ch = cv.waitKey()
if ch == 27:
break
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+111
View File
@@ -0,0 +1,111 @@
#!/usr/bin/env python
'''
Planar augmented reality
==================
This sample shows an example of augmented reality overlay over a planar object
tracked by PlaneTracker from plane_tracker.py. solvePnP function is used to
estimate the tracked object location in 3d space.
video: http://www.youtube.com/watch?v=pzVbhxx6aog
Usage
-----
plane_ar.py [<video source>]
Keys:
SPACE - pause video
c - clear targets
Select a textured planar object to track by drawing a box with a mouse.
Use 'focal' slider to adjust to camera focal length for proper video augmentation.
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
import video
import common
from plane_tracker import PlaneTracker
from video import presets
# Simple model of a house - cube with a triangular prism "roof"
ar_verts = np.float32([[0, 0, 0], [0, 1, 0], [1, 1, 0], [1, 0, 0],
[0, 0, 1], [0, 1, 1], [1, 1, 1], [1, 0, 1],
[0, 0.5, 2], [1, 0.5, 2]])
ar_edges = [(0, 1), (1, 2), (2, 3), (3, 0),
(4, 5), (5, 6), (6, 7), (7, 4),
(0, 4), (1, 5), (2, 6), (3, 7),
(4, 8), (5, 8), (6, 9), (7, 9), (8, 9)]
class App:
def __init__(self, src):
self.cap = video.create_capture(src, presets['book'])
self.frame = None
self.paused = False
self.tracker = PlaneTracker()
cv.namedWindow('plane')
cv.createTrackbar('focal', 'plane', 25, 50, common.nothing)
self.rect_sel = common.RectSelector('plane', self.on_rect)
def on_rect(self, rect):
self.tracker.add_target(self.frame, rect)
def run(self):
while True:
playing = not self.paused and not self.rect_sel.dragging
if playing or self.frame is None:
ret, frame = self.cap.read()
if not ret:
break
self.frame = frame.copy()
vis = self.frame.copy()
if playing:
tracked = self.tracker.track(self.frame)
for tr in tracked:
cv.polylines(vis, [np.int32(tr.quad)], True, (255, 255, 255), 2)
for (x, y) in np.int32(tr.p1):
cv.circle(vis, (x, y), 2, (255, 255, 255))
self.draw_overlay(vis, tr)
self.rect_sel.draw(vis)
cv.imshow('plane', vis)
ch = cv.waitKey(1)
if ch == ord(' '):
self.paused = not self.paused
if ch == ord('c'):
self.tracker.clear()
if ch == 27:
break
def draw_overlay(self, vis, tracked):
x0, y0, x1, y1 = tracked.target.rect
quad_3d = np.float32([[x0, y0, 0], [x1, y0, 0], [x1, y1, 0], [x0, y1, 0]])
fx = 0.5 + cv.getTrackbarPos('focal', 'plane') / 50.0
h, w = vis.shape[:2]
K = np.float64([[fx*w, 0, 0.5*(w-1)],
[0, fx*w, 0.5*(h-1)],
[0.0,0.0, 1.0]])
dist_coef = np.zeros(4)
_ret, rvec, tvec = cv.solvePnP(quad_3d, tracked.quad, K, dist_coef)
verts = ar_verts * [(x1-x0), (y1-y0), -(x1-x0)*0.3] + (x0, y0, 0)
verts = cv.projectPoints(verts, rvec, tvec, K, dist_coef)[0].reshape(-1, 2)
for i, j in ar_edges:
(x0, y0), (x1, y1) = verts[i], verts[j]
cv.line(vis, (int(x0), int(y0)), (int(x1), int(y1)), (255, 255, 0), 2)
if __name__ == '__main__':
print(__doc__)
import sys
try:
video_src = sys.argv[1]
except:
video_src = 0
App(video_src).run()
+189
View File
@@ -0,0 +1,189 @@
#!/usr/bin/env python
'''
Multitarget planar tracking
==================
Example of using features2d framework for interactive video homography matching.
ORB features and FLANN matcher are used. This sample provides PlaneTracker class
and an example of its usage.
video: http://www.youtube.com/watch?v=pzVbhxx6aog
Usage
-----
plane_tracker.py [<video source>]
Keys:
SPACE - pause video
c - clear targets
Select a textured planar object to track by drawing a box with a mouse.
'''
# Python 2/3 compatibility
from __future__ import print_function
import sys
PY3 = sys.version_info[0] == 3
if PY3:
xrange = range
import numpy as np
import cv2 as cv
# built-in modules
from collections import namedtuple
# local modules
import video
import common
from video import presets
FLANN_INDEX_KDTREE = 1
FLANN_INDEX_LSH = 6
flann_params= dict(algorithm = FLANN_INDEX_LSH,
table_number = 6, # 12
key_size = 12, # 20
multi_probe_level = 1) #2
MIN_MATCH_COUNT = 10
'''
image - image to track
rect - tracked rectangle (x1, y1, x2, y2)
keypoints - keypoints detected inside rect
descrs - their descriptors
data - some user-provided data
'''
PlanarTarget = namedtuple('PlaneTarget', 'image, rect, keypoints, descrs, data')
'''
target - reference to PlanarTarget
p0 - matched points coords in target image
p1 - matched points coords in input frame
H - homography matrix from p0 to p1
quad - target boundary quad in input frame
'''
TrackedTarget = namedtuple('TrackedTarget', 'target, p0, p1, H, quad')
class PlaneTracker:
def __init__(self):
self.detector = cv.ORB_create( nfeatures = 1000 )
self.matcher = cv.FlannBasedMatcher(flann_params, {}) # bug : need to pass empty dict (#1329)
self.targets = []
self.frame_points = []
def add_target(self, image, rect, data=None):
'''Add a new tracking target.'''
x0, y0, x1, y1 = rect
raw_points, raw_descrs = self.detect_features(image)
points, descs = [], []
for kp, desc in zip(raw_points, raw_descrs):
x, y = kp.pt
if x0 <= x <= x1 and y0 <= y <= y1:
points.append(kp)
descs.append(desc)
descs = np.uint8(descs)
self.matcher.add([descs])
target = PlanarTarget(image = image, rect=rect, keypoints = points, descrs=descs, data=data)
self.targets.append(target)
def clear(self):
'''Remove all targets'''
self.targets = []
self.matcher.clear()
def track(self, frame):
'''Returns a list of detected TrackedTarget objects'''
self.frame_points, frame_descrs = self.detect_features(frame)
if len(self.frame_points) < MIN_MATCH_COUNT:
return []
matches = self.matcher.knnMatch(frame_descrs, k = 2)
matches = [m[0] for m in matches if len(m) == 2 and m[0].distance < m[1].distance * 0.75]
if len(matches) < MIN_MATCH_COUNT:
return []
matches_by_id = [[] for _ in xrange(len(self.targets))]
for m in matches:
matches_by_id[m.imgIdx].append(m)
tracked = []
for imgIdx, matches in enumerate(matches_by_id):
if len(matches) < MIN_MATCH_COUNT:
continue
target = self.targets[imgIdx]
p0 = [target.keypoints[m.trainIdx].pt for m in matches]
p1 = [self.frame_points[m.queryIdx].pt for m in matches]
p0, p1 = np.float32((p0, p1))
H, status = cv.findHomography(p0, p1, cv.RANSAC, 3.0)
status = status.ravel() != 0
if status.sum() < MIN_MATCH_COUNT:
continue
p0, p1 = p0[status], p1[status]
x0, y0, x1, y1 = target.rect
quad = np.float32([[x0, y0], [x1, y0], [x1, y1], [x0, y1]])
quad = cv.perspectiveTransform(quad.reshape(1, -1, 2), H).reshape(-1, 2)
track = TrackedTarget(target=target, p0=p0, p1=p1, H=H, quad=quad)
tracked.append(track)
tracked.sort(key = lambda t: len(t.p0), reverse=True)
return tracked
def detect_features(self, frame):
'''detect_features(self, frame) -> keypoints, descrs'''
keypoints, descrs = self.detector.detectAndCompute(frame, None)
if descrs is None: # detectAndCompute returns descs=None if not keypoints found
descrs = []
return keypoints, descrs
class App:
def __init__(self, src):
self.cap = video.create_capture(src, presets['book'])
self.frame = None
self.paused = False
self.tracker = PlaneTracker()
cv.namedWindow('plane')
self.rect_sel = common.RectSelector('plane', self.on_rect)
def on_rect(self, rect):
self.tracker.add_target(self.frame, rect)
def run(self):
while True:
playing = not self.paused and not self.rect_sel.dragging
if playing or self.frame is None:
ret, frame = self.cap.read()
if not ret:
break
self.frame = frame.copy()
vis = self.frame.copy()
if playing:
tracked = self.tracker.track(self.frame)
for tr in tracked:
cv.polylines(vis, [np.int32(tr.quad)], True, (255, 255, 255), 2)
for (x, y) in np.int32(tr.p1):
cv.circle(vis, (x, y), 2, (255, 255, 255))
self.rect_sel.draw(vis)
cv.imshow('plane', vis)
ch = cv.waitKey(1)
if ch == ord(' '):
self.paused = not self.paused
if ch == ord('c'):
self.tracker.clear()
if ch == 27:
break
if __name__ == '__main__':
print(__doc__)
import sys
try:
video_src = sys.argv[1]
except:
video_src = 0
App(video_src).run()
+275
View File
@@ -0,0 +1,275 @@
#!/usr/bin/env python
'''
This program detects the QR-codes using OpenCV Library.
Usage:
qrcode.py
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
import argparse
import sys
PY3 = sys.version_info[0] == 3
if PY3:
xrange = range
# Colors for distinguishing multiple QR codes visually
QR_COLORS = [
(0, 255, 0), # green
(255, 0, 0), # blue
(0, 0, 255), # red
(255, 255, 0), # cyan
(0, 255, 255), # yellow
(255, 0, 255), # magenta
(128, 255, 0), # lime
(255, 128, 0), # orange
]
class QrSample:
def __init__(self, args):
self.fname = ''
self.fext = ''
self.fsaveid = 0
self.input = args.input
self.detect = args.detect
self.out = args.out
self.multi = args.multi
self.saveDetections = args.save_detections
self.saveAll = args.save_all
self.arucoBased = args.aruco_based
def getQRModeString(self):
msg1 = "multi " if self.multi else ""
msg2 = "detector" if self.detect else "decoder"
msg = "QR {:s}{:s}".format(msg1, msg2)
return msg
def drawFPS(self, result, fps):
message = '{:.2f} FPS({:s})'.format(fps, self.getQRModeString())
cv.putText(result, message, (20, 20), 1,
cv.FONT_HERSHEY_DUPLEX, (0, 0, 255))
def drawQRCodeContours(self, image, cnt, color=(0, 255, 0)):
if cnt.size != 0:
rows, cols, _ = image.shape
show_radius = 2.813 * ((rows / cols) if rows > cols else (cols / rows))
contour_radius = show_radius * 0.4
cv.drawContours(image, [cnt], 0, color, int(round(contour_radius)))
tpl = cnt.reshape((-1, 2))
for x in tuple(tpl.tolist()):
cv.circle(image, tuple(x), int(round(contour_radius)), color, -1)
def drawQRCodeResults(self, result, points, decode_info, fps):
n = len(points)
if isinstance(decode_info, str):
decode_info = [decode_info]
if n > 0:
for i in range(n):
cnt = np.array(points[i]).reshape((-1, 1, 2)).astype(np.int32)
color = QR_COLORS[i % len(QR_COLORS)]
self.drawQRCodeContours(result, cnt, color)
msg = 'QR[{:d}]@{} : '.format(i, *(cnt.reshape(1, -1).tolist()))
print(msg, end="")
if len(decode_info) > i:
if decode_info[i]:
print("'", decode_info[i], "'")
else:
print("Can't decode QR code")
else:
print("Decode information is not available (disabled)")
else:
print("QRCode not detected!")
self.drawFPS(result, fps)
def runQR(self, qrCode, inputimg):
if not self.multi:
if not self.detect:
decode_info, points, _ = qrCode.detectAndDecode(inputimg)
dec_info = decode_info
else:
_, points = qrCode.detect(inputimg)
dec_info = []
else:
if not self.detect:
_, decode_info, points, _ = qrCode.detectAndDecodeMulti(
inputimg)
dec_info = decode_info
else:
_, points = qrCode.detectMulti(inputimg)
dec_info = []
if points is None:
points = []
return points, dec_info
def DetectQRFrmImage(self, inputfile):
inputimg = cv.imread(inputfile, cv.IMREAD_COLOR)
if inputimg is None:
print('ERROR: Can not read image: {}'.format(inputfile))
return
print('Run {:s} on image [{:d}x{:d}]'.format(
self.getQRModeString(), inputimg.shape[1], inputimg.shape[0]))
if self.arucoBased:
qrCode = cv.QRCodeDetectorAruco()
else:
qrCode = cv.QRCodeDetector()
count = 10
timer = cv.TickMeter()
for _ in range(count):
timer.start()
points, decode_info = self.runQR(qrCode, inputimg)
timer.stop()
fps = count / timer.getTimeSec()
print('FPS: {}'.format(fps))
result = inputimg
self.drawQRCodeResults(result, points, decode_info, fps)
cv.imshow("QR", result)
cv.waitKey(1)
if self.out != '':
outfile = self.fname + self.fext
print("Saving Result: {}".format(outfile))
cv.imwrite(outfile, result)
print("Press any key to exit ...")
cv.waitKey(0)
print("Exit")
def processQRCodeDetection(self, qrcode, frame):
if len(frame.shape) == 2:
result = cv.cvtColor(frame, cv.COLOR_GRAY2BGR)
else:
result = frame
print('Run {:s} on video frame [{:d}x{:d}]'.format(
self.getQRModeString(), frame.shape[1], frame.shape[0]))
timer = cv.TickMeter()
timer.start()
points, decode_info = self.runQR(qrcode, frame)
timer.stop()
fps = 1 / timer.getTimeSec()
self.drawQRCodeResults(result, points, decode_info, fps)
return fps, result, points
def DetectQRFrmCamera(self):
cap = cv.VideoCapture(0)
if not cap.isOpened():
print("Cannot open the camera")
return
print("Press 'm' to switch between detectAndDecode and detectAndDecodeMulti")
print("Press 'd' to switch between decoder and detector")
print("Press ' ' (space) to save result into images")
print("Press 'ESC' to exit")
if self.arucoBased:
qrcode = cv.QRCodeDetectorAruco()
else:
qrcode = cv.QRCodeDetector()
while True:
ret, frame = cap.read()
if not ret:
print("End of video stream")
break
forcesave = self.saveAll
result = frame
try:
fps, result, corners = self.processQRCodeDetection(qrcode, frame)
print('FPS: {:.2f}'.format(fps))
forcesave |= self.saveDetections and (len(corners) != 0)
except cv.error as e:
print("Error exception: ", e)
forcesave = True
cv.imshow("QR code", result)
code = cv.waitKey(1)
if code < 0 and (not forcesave):
continue
if code == ord(' ') or forcesave:
fsuffix = '-{:05d}'.format(self.fsaveid)
self.fsaveid += 1
fname_in = self.fname + fsuffix + "_input.png"
print("Saving QR code detection result: '{}' ...".format(fname_in))
cv.imwrite(fname_in, frame)
print("Saved")
if code == ord('m'):
self.multi = not self.multi
msg = 'Switching QR code mode ==> {:s}'.format(
"detectAndDecodeMulti" if self.multi else "detectAndDecode")
print(msg)
if code == ord('d'):
self.detect = not self.detect
msg = 'Switching QR code mode ==> {:s}'.format(
"detect" if self.detect else "decode")
print(msg)
if code == 27:
print("'ESC' is pressed. Exiting...")
break
print("Exit.")
def main():
parser = argparse.ArgumentParser(
description='This program detects the QR-codes input images using OpenCV Library.')
parser.add_argument(
'-i',
'--input',
help="input image path (for example, 'opencv_extra/testdata/cv/qrcode/multiple/*_qrcodes.png)",
default="",
metavar="")
parser.add_argument(
'--aruco_based',
help="use aruco-based detector",
action='store_true')
parser.add_argument(
'-d',
'--detect',
help="detect QR code only (skip decoding) (default: False)",
action='store_true')
parser.add_argument(
'-m',
'--multi',
help="enable multiple qr-codes detection",
action='store_true')
parser.add_argument(
'-o',
'--out',
help="path to result file (default: qr_code.png)",
default="qr_code.png",
metavar="")
parser.add_argument(
'--save_detections',
help="save all QR detections (video mode only)",
action='store_true')
parser.add_argument(
'--save_all',
help="save all processed frames (video mode only)",
action='store_true')
args = parser.parse_args()
qrinst = QrSample(args)
if args.out != '':
index = args.out.rfind('.')
if index != -1:
qrinst.fname = args.out[:index]
qrinst.fext = args.out[index:]
else:
qrinst.fname = args.out
qrinst.fext = ".png"
if args.input != '':
qrinst.DetectQRFrmImage(args.input)
else:
qrinst.DetectQRFrmCamera()
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+63
View File
@@ -0,0 +1,63 @@
#!/usr/bin/env python
'''
Simple "Square Detector" program.
Loads several images sequentially and tries to find squares in each image.
'''
# Python 2/3 compatibility
from __future__ import print_function
import sys
PY3 = sys.version_info[0] == 3
if PY3:
xrange = range
import numpy as np
import cv2 as cv
def angle_cos(p0, p1, p2):
d1, d2 = (p0-p1).astype('float'), (p2-p1).astype('float')
return abs( np.dot(d1, d2) / np.sqrt( np.dot(d1, d1)*np.dot(d2, d2) ) )
def find_squares(img):
img = cv.GaussianBlur(img, (5, 5), 0)
squares = []
for gray in cv.split(img):
for thrs in xrange(0, 255, 26):
if thrs == 0:
bin = cv.Canny(gray, 0, 50, apertureSize=5)
bin = cv.dilate(bin, None)
else:
_retval, bin = cv.threshold(gray, thrs, 255, cv.THRESH_BINARY)
contours, _hierarchy = cv.findContours(bin, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
for cnt in contours:
cnt_len = cv.arcLength(cnt, True)
cnt = cv.approxPolyDP(cnt, 0.02*cnt_len, True)
if len(cnt) == 4 and cv.contourArea(cnt) > 1000 and cv.isContourConvex(cnt):
cnt = cnt.reshape(-1, 2)
max_cos = np.max([angle_cos( cnt[i], cnt[(i+1) % 4], cnt[(i+2) % 4] ) for i in xrange(4)])
if max_cos < 0.1:
squares.append(cnt)
return squares
def main():
from glob import glob
for fn in glob('../data/pic*.png'):
img = cv.imread(fn)
squares = find_squares(img)
cv.drawContours( img, squares, -1, (0, 255, 0), 3 )
cv.imshow('squares', img)
ch = cv.waitKey()
if ch == 27:
break
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+85
View File
@@ -0,0 +1,85 @@
#!/usr/bin/env python
'''
Simple example of stereo image matching and point cloud generation.
Resulting .ply file cam be easily viewed using MeshLab ( http://meshlab.sourceforge.net/ )
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
ply_header = '''ply
format ascii 1.0
element vertex %(vert_num)d
property float x
property float y
property float z
property uchar red
property uchar green
property uchar blue
end_header
'''
def write_ply(fn, verts, colors):
verts = verts.reshape(-1, 3)
colors = colors.reshape(-1, 3)
verts = np.hstack([verts, colors])
with open(fn, 'wb') as f:
f.write((ply_header % dict(vert_num=len(verts))).encode('utf-8'))
np.savetxt(f, verts, fmt='%f %f %f %d %d %d ')
def main():
print('loading images...')
imgL = cv.pyrDown(cv.imread(cv.samples.findFile('aloeL.jpg'))) # downscale images for faster processing
imgR = cv.pyrDown(cv.imread(cv.samples.findFile('aloeR.jpg')))
# disparity range is tuned for 'aloe' image pair
window_size = 3
min_disp = 16
num_disp = 112-min_disp
stereo = cv.StereoSGBM_create(minDisparity = min_disp,
numDisparities = num_disp,
blockSize = 16,
P1 = 8*3*window_size**2,
P2 = 32*3*window_size**2,
disp12MaxDiff = 1,
uniquenessRatio = 10,
speckleWindowSize = 100,
speckleRange = 32
)
print('computing disparity...')
disp = stereo.compute(imgL, imgR).astype(np.float32) / 16.0
print('generating 3d point cloud...',)
h, w = imgL.shape[:2]
f = 0.8*w # guess for focal length
Q = np.float32([[1, 0, 0, -0.5*w],
[0,-1, 0, 0.5*h], # turn points 180 deg around x-axis,
[0, 0, 0, -f], # so that y-axis looks up
[0, 0, 1, 0]])
points = cv.reprojectImageTo3D(disp, Q)
colors = cv.cvtColor(imgL, cv.COLOR_BGR2RGB)
mask = disp > disp.min()
out_points = points[mask]
out_colors = colors[mask]
out_fn = 'out.ply'
write_ply(out_fn, out_points, out_colors)
print('%s saved' % out_fn)
cv.imshow('left', imgL)
cv.imshow('disparity', (disp-min_disp)/num_disp)
cv.waitKey()
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+64
View File
@@ -0,0 +1,64 @@
#!/usr/bin/env python
'''
Stitching sample
================
Show how to use Stitcher API from python in a simple way to stitch panoramas
or scans.
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
import argparse
import sys
modes = (cv.Stitcher_PANORAMA, cv.Stitcher_SCANS)
parser = argparse.ArgumentParser(prog='stitching.py', description='Stitching sample.')
parser.add_argument('--mode',
type = int, choices = modes, default = cv.Stitcher_PANORAMA,
help = 'Determines configuration of stitcher. The default is `PANORAMA` (%d), '
'mode suitable for creating photo panoramas. Option `SCANS` (%d) is suitable '
'for stitching materials under affine transformation, such as scans.' % modes)
parser.add_argument('--output', default = 'result.jpg',
help = 'Resulting image. The default is `result.jpg`.')
parser.add_argument('img', nargs='+', help = 'input images')
__doc__ += '\n' + parser.format_help()
def main():
args = parser.parse_args()
# read input images
imgs = []
for img_name in args.img:
img = cv.imread(cv.samples.findFile(img_name))
if img is None:
print("can't read image " + img_name)
sys.exit(-1)
imgs.append(img)
#![stitching]
stitcher = cv.Stitcher.create(args.mode)
status, pano = stitcher.stitch(imgs)
if status != cv.Stitcher_OK:
print("Can't stitch images, error code = %d" % status)
sys.exit(-1)
#![stitching]
cv.imwrite(args.output, pano)
print("stitching completed successfully. %s saved!" % args.output)
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+520
View File
@@ -0,0 +1,520 @@
"""
Stitching sample (advanced)
===========================
Show how to use Stitcher API from python.
"""
# Python 2/3 compatibility
from __future__ import print_function
import argparse
from collections import OrderedDict
import cv2 as cv
import numpy as np
EXPOS_COMP_CHOICES = OrderedDict()
EXPOS_COMP_CHOICES['gain_blocks'] = cv.detail.ExposureCompensator_GAIN_BLOCKS
EXPOS_COMP_CHOICES['gain'] = cv.detail.ExposureCompensator_GAIN
EXPOS_COMP_CHOICES['channel'] = cv.detail.ExposureCompensator_CHANNELS
EXPOS_COMP_CHOICES['channel_blocks'] = cv.detail.ExposureCompensator_CHANNELS_BLOCKS
EXPOS_COMP_CHOICES['no'] = cv.detail.ExposureCompensator_NO
BA_COST_CHOICES = OrderedDict()
BA_COST_CHOICES['ray'] = cv.detail_BundleAdjusterRay
BA_COST_CHOICES['reproj'] = cv.detail_BundleAdjusterReproj
BA_COST_CHOICES['affine'] = cv.detail_BundleAdjusterAffinePartial
BA_COST_CHOICES['no'] = cv.detail_NoBundleAdjuster
FEATURES_FIND_CHOICES = OrderedDict()
try:
cv.xfeatures2d_SURF.create() # check if the function can be called
FEATURES_FIND_CHOICES['surf'] = cv.xfeatures2d_SURF.create
except (AttributeError, cv.error) as e:
print("SURF not available")
# if SURF not available, ORB is default
FEATURES_FIND_CHOICES['orb'] = cv.ORB.create
try:
FEATURES_FIND_CHOICES['sift'] = cv.SIFT_create
except AttributeError:
print("SIFT not available")
try:
FEATURES_FIND_CHOICES['brisk'] = cv.BRISK_create
except AttributeError:
print("BRISK not available")
try:
FEATURES_FIND_CHOICES['akaze'] = cv.AKAZE_create
except AttributeError:
print("AKAZE not available")
SEAM_FIND_CHOICES = OrderedDict()
SEAM_FIND_CHOICES['gc_color'] = cv.detail_GraphCutSeamFinder('COST_COLOR')
SEAM_FIND_CHOICES['gc_colorgrad'] = cv.detail_GraphCutSeamFinder('COST_COLOR_GRAD')
SEAM_FIND_CHOICES['dp_color'] = cv.detail_DpSeamFinder('COLOR')
SEAM_FIND_CHOICES['dp_colorgrad'] = cv.detail_DpSeamFinder('COLOR_GRAD')
SEAM_FIND_CHOICES['voronoi'] = cv.detail.SeamFinder_createDefault(cv.detail.SeamFinder_VORONOI_SEAM)
SEAM_FIND_CHOICES['no'] = cv.detail.SeamFinder_createDefault(cv.detail.SeamFinder_NO)
ESTIMATOR_CHOICES = OrderedDict()
ESTIMATOR_CHOICES['homography'] = cv.detail_HomographyBasedEstimator
ESTIMATOR_CHOICES['affine'] = cv.detail_AffineBasedEstimator
WARP_CHOICES = (
'spherical',
'plane',
'affine',
'cylindrical',
'fisheye',
'stereographic',
'compressedPlaneA2B1',
'compressedPlaneA1.5B1',
'compressedPlanePortraitA2B1',
'compressedPlanePortraitA1.5B1',
'paniniA2B1',
'paniniA1.5B1',
'paniniPortraitA2B1',
'paniniPortraitA1.5B1',
'mercator',
'transverseMercator',
)
WAVE_CORRECT_CHOICES = OrderedDict()
WAVE_CORRECT_CHOICES['horiz'] = cv.detail.WAVE_CORRECT_HORIZ
WAVE_CORRECT_CHOICES['no'] = None
WAVE_CORRECT_CHOICES['vert'] = cv.detail.WAVE_CORRECT_VERT
BLEND_CHOICES = ('multiband', 'feather', 'no',)
parser = argparse.ArgumentParser(
prog="stitching_detailed.py", description="Rotation model images stitcher"
)
parser.add_argument(
'img_names', nargs='+',
help="Files to stitch", type=str
)
parser.add_argument(
'--try_cuda',
action='store_true',
help="Try to use CUDA. The default value is no. All default values are for CPU mode.",
)
parser.add_argument(
'--work_megapix', action='store', default=0.6,
help="Resolution for image registration step. The default is 0.6 Mpx",
type=float, dest='work_megapix'
)
parser.add_argument(
'--features', action='store', default=list(FEATURES_FIND_CHOICES.keys())[0],
help="Type of features used for images matching. The default is '%s'." % list(FEATURES_FIND_CHOICES.keys())[0],
choices=FEATURES_FIND_CHOICES.keys(),
type=str, dest='features'
)
parser.add_argument(
'--matcher', action='store', default='homography',
help="Matcher used for pairwise image matching. The default is 'homography'.",
choices=('homography', 'affine'),
type=str, dest='matcher'
)
parser.add_argument(
'--estimator', action='store', default=list(ESTIMATOR_CHOICES.keys())[0],
help="Type of estimator used for transformation estimation. The default is '%s'." % list(ESTIMATOR_CHOICES.keys())[0],
choices=ESTIMATOR_CHOICES.keys(),
type=str, dest='estimator'
)
parser.add_argument(
'--match_conf', action='store',
help="Confidence for feature matching step. The default is 0.3 for ORB and 0.65 for other feature types.",
type=float, dest='match_conf'
)
parser.add_argument(
'--conf_thresh', action='store', default=1.0,
help="Threshold for two images are from the same panorama confidence.The default is 1.0.",
type=float, dest='conf_thresh'
)
parser.add_argument(
'--ba', action='store', default=list(BA_COST_CHOICES.keys())[0],
help="Bundle adjustment cost function. The default is '%s'." % list(BA_COST_CHOICES.keys())[0],
choices=BA_COST_CHOICES.keys(),
type=str, dest='ba'
)
parser.add_argument(
'--ba_refine_mask', action='store', default='xxxxx',
help="Set refinement mask for bundle adjustment. It looks like 'x_xxx', "
"where 'x' means refine respective parameter and '_' means don't refine, "
"and has the following format:<fx><skew><ppx><aspect><ppy>. "
"The default mask is 'xxxxx'. "
"If bundle adjustment doesn't support estimation of selected parameter then "
"the respective flag is ignored.",
type=str, dest='ba_refine_mask'
)
parser.add_argument(
'--wave_correct', action='store', default=list(WAVE_CORRECT_CHOICES.keys())[0],
help="Perform wave effect correction. The default is '%s'" % list(WAVE_CORRECT_CHOICES.keys())[0],
choices=WAVE_CORRECT_CHOICES.keys(),
type=str, dest='wave_correct'
)
parser.add_argument(
'--save_graph', action='store', default=None,
help="Save matches graph represented in DOT language to <file_name> file.",
type=str, dest='save_graph'
)
parser.add_argument(
'--warp', action='store', default=WARP_CHOICES[0],
help="Warp surface type. The default is '%s'." % WARP_CHOICES[0],
choices=WARP_CHOICES,
type=str, dest='warp'
)
parser.add_argument(
'--seam_megapix', action='store', default=0.1,
help="Resolution for seam estimation step. The default is 0.1 Mpx.",
type=float, dest='seam_megapix'
)
parser.add_argument(
'--seam', action='store', default=list(SEAM_FIND_CHOICES.keys())[0],
help="Seam estimation method. The default is '%s'." % list(SEAM_FIND_CHOICES.keys())[0],
choices=SEAM_FIND_CHOICES.keys(),
type=str, dest='seam'
)
parser.add_argument(
'--compose_megapix', action='store', default=-1,
help="Resolution for compositing step. Use -1 for original resolution. The default is -1",
type=float, dest='compose_megapix'
)
parser.add_argument(
'--expos_comp', action='store', default=list(EXPOS_COMP_CHOICES.keys())[0],
help="Exposure compensation method. The default is '%s'." % list(EXPOS_COMP_CHOICES.keys())[0],
choices=EXPOS_COMP_CHOICES.keys(),
type=str, dest='expos_comp'
)
parser.add_argument(
'--expos_comp_nr_feeds', action='store', default=1,
help="Number of exposure compensation feed.",
type=np.int32, dest='expos_comp_nr_feeds'
)
parser.add_argument(
'--expos_comp_nr_filtering', action='store', default=2,
help="Number of filtering iterations of the exposure compensation gains.",
type=float, dest='expos_comp_nr_filtering'
)
parser.add_argument(
'--expos_comp_block_size', action='store', default=32,
help="BLock size in pixels used by the exposure compensator. The default is 32.",
type=np.int32, dest='expos_comp_block_size'
)
parser.add_argument(
'--blend', action='store', default=BLEND_CHOICES[0],
help="Blending method. The default is '%s'." % BLEND_CHOICES[0],
choices=BLEND_CHOICES,
type=str, dest='blend'
)
parser.add_argument(
'--blend_strength', action='store', default=5,
help="Blending strength from [0,100] range. The default is 5",
type=np.int32, dest='blend_strength'
)
parser.add_argument(
'--output', action='store', default='result.jpg',
help="The default is 'result.jpg'",
type=str, dest='output'
)
parser.add_argument(
'--timelapse', action='store', default=None,
help="Output warped images separately as frames of a time lapse movie, "
"with 'fixed_' prepended to input file names.",
type=str, dest='timelapse'
)
parser.add_argument(
'--rangewidth', action='store', default=-1,
help="uses range_width to limit number of images to match with.",
type=int, dest='rangewidth'
)
__doc__ += '\n' + parser.format_help()
def get_matcher(args):
try_cuda = args.try_cuda
matcher_type = args.matcher
if args.match_conf is None:
if args.features == 'orb':
match_conf = 0.3
else:
match_conf = 0.65
else:
match_conf = args.match_conf
range_width = args.rangewidth
if matcher_type == "affine":
matcher = cv.detail_AffineBestOf2NearestMatcher(False, try_cuda, match_conf)
elif range_width == -1:
matcher = cv.detail_BestOf2NearestMatcher(try_cuda, match_conf)
else:
matcher = cv.detail_BestOf2NearestRangeMatcher(range_width, try_cuda, match_conf)
return matcher
def get_compensator(args):
expos_comp_type = EXPOS_COMP_CHOICES[args.expos_comp]
expos_comp_nr_feeds = args.expos_comp_nr_feeds
expos_comp_block_size = args.expos_comp_block_size
# expos_comp_nr_filtering = args.expos_comp_nr_filtering
if expos_comp_type == cv.detail.ExposureCompensator_CHANNELS:
compensator = cv.detail_ChannelsCompensator(expos_comp_nr_feeds)
# compensator.setNrGainsFilteringIterations(expos_comp_nr_filtering)
elif expos_comp_type == cv.detail.ExposureCompensator_CHANNELS_BLOCKS:
compensator = cv.detail_BlocksChannelsCompensator(
expos_comp_block_size, expos_comp_block_size,
expos_comp_nr_feeds
)
# compensator.setNrGainsFilteringIterations(expos_comp_nr_filtering)
else:
compensator = cv.detail.ExposureCompensator_createDefault(expos_comp_type)
return compensator
def main():
args = parser.parse_args()
img_names = args.img_names
print(img_names)
work_megapix = args.work_megapix
seam_megapix = args.seam_megapix
compose_megapix = args.compose_megapix
conf_thresh = args.conf_thresh
ba_refine_mask = args.ba_refine_mask
wave_correct = WAVE_CORRECT_CHOICES[args.wave_correct]
if args.save_graph is None:
save_graph = False
else:
save_graph = True
warp_type = args.warp
blend_type = args.blend
blend_strength = args.blend_strength
result_name = args.output
if args.timelapse is not None:
timelapse = True
if args.timelapse == "as_is":
timelapse_type = cv.detail.Timelapser_AS_IS
elif args.timelapse == "crop":
timelapse_type = cv.detail.Timelapser_CROP
else:
print("Bad timelapse method")
exit()
else:
timelapse = False
finder = FEATURES_FIND_CHOICES[args.features]()
seam_work_aspect = 1
full_img_sizes = []
features = []
images = []
is_work_scale_set = False
is_seam_scale_set = False
is_compose_scale_set = False
for name in img_names:
full_img = cv.imread(cv.samples.findFile(name))
if full_img is None:
print("Cannot read image ", name)
exit()
full_img_sizes.append((full_img.shape[1], full_img.shape[0]))
if work_megapix < 0:
img = full_img
work_scale = 1
is_work_scale_set = True
else:
if is_work_scale_set is False:
work_scale = min(1.0, np.sqrt(work_megapix * 1e6 / (full_img.shape[0] * full_img.shape[1])))
is_work_scale_set = True
img = cv.resize(src=full_img, dsize=None, fx=work_scale, fy=work_scale, interpolation=cv.INTER_LINEAR_EXACT)
if is_seam_scale_set is False:
if seam_megapix > 0:
seam_scale = min(1.0, np.sqrt(seam_megapix * 1e6 / (full_img.shape[0] * full_img.shape[1])))
else:
seam_scale = 1.0
seam_work_aspect = seam_scale / work_scale
is_seam_scale_set = True
img_feat = cv.detail.computeImageFeatures2(finder, img)
features.append(img_feat)
img = cv.resize(src=full_img, dsize=None, fx=seam_scale, fy=seam_scale, interpolation=cv.INTER_LINEAR_EXACT)
images.append(img)
matcher = get_matcher(args)
p = matcher.apply2(features)
matcher.collectGarbage()
if save_graph:
with open(args.save_graph, 'w') as fh:
fh.write(cv.detail.matchesGraphAsString(img_names, p, conf_thresh))
indices = cv.detail.leaveBiggestComponent(features, p, conf_thresh)
img_subset = []
img_names_subset = []
full_img_sizes_subset = []
for i in range(len(indices)):
img_names_subset.append(img_names[indices[i]])
img_subset.append(images[indices[i]])
full_img_sizes_subset.append(full_img_sizes[indices[i]])
images = img_subset
img_names = img_names_subset
full_img_sizes = full_img_sizes_subset
num_images = len(img_names)
if num_images < 2:
print("Need more images")
exit()
estimator = ESTIMATOR_CHOICES[args.estimator]()
b, cameras = estimator.apply(features, p, None)
if not b:
print("Homography estimation failed.")
exit()
for cam in cameras:
cam.R = cam.R.astype(np.float32)
adjuster = BA_COST_CHOICES[args.ba]()
adjuster.setConfThresh(conf_thresh)
refine_mask = np.zeros((3, 3), np.uint8)
if ba_refine_mask[0] == 'x':
refine_mask[0, 0] = 1
if ba_refine_mask[1] == 'x':
refine_mask[0, 1] = 1
if ba_refine_mask[2] == 'x':
refine_mask[0, 2] = 1
if ba_refine_mask[3] == 'x':
refine_mask[1, 1] = 1
if ba_refine_mask[4] == 'x':
refine_mask[1, 2] = 1
adjuster.setRefinementMask(refine_mask)
b, cameras = adjuster.apply(features, p, cameras)
if not b:
print("Camera parameters adjusting failed.")
exit()
focals = []
for cam in cameras:
focals.append(cam.focal)
focals.sort()
if len(focals) % 2 == 1:
warped_image_scale = focals[len(focals) // 2]
else:
warped_image_scale = (focals[len(focals) // 2] + focals[len(focals) // 2 - 1]) / 2
if wave_correct is not None:
rmats = []
for cam in cameras:
rmats.append(np.copy(cam.R))
rmats = cv.detail.waveCorrect(rmats, wave_correct)
for idx, cam in enumerate(cameras):
cam.R = rmats[idx]
corners = []
masks_warped = []
images_warped = []
sizes = []
masks = []
for i in range(0, num_images):
um = cv.UMat(255 * np.ones((images[i].shape[0], images[i].shape[1]), np.uint8))
masks.append(um)
warper = cv.PyRotationWarper(warp_type, warped_image_scale * seam_work_aspect) # warper could be nullptr?
for idx in range(0, num_images):
K = cameras[idx].K().astype(np.float32)
swa = seam_work_aspect
K[0, 0] *= swa
K[0, 2] *= swa
K[1, 1] *= swa
K[1, 2] *= swa
corner, image_wp = warper.warp(images[idx], K, cameras[idx].R, cv.INTER_LINEAR, cv.BORDER_REFLECT)
corners.append(corner)
sizes.append((image_wp.shape[1], image_wp.shape[0]))
images_warped.append(image_wp)
p, mask_wp = warper.warp(masks[idx], K, cameras[idx].R, cv.INTER_NEAREST, cv.BORDER_CONSTANT)
masks_warped.append(mask_wp.get())
images_warped_f = []
for img in images_warped:
imgf = img.astype(np.float32)
images_warped_f.append(imgf)
compensator = get_compensator(args)
compensator.feed(corners=corners, images=images_warped, masks=masks_warped)
seam_finder = SEAM_FIND_CHOICES[args.seam]
masks_warped = seam_finder.find(images_warped_f, corners, masks_warped)
compose_scale = 1
corners = []
sizes = []
blender = None
timelapser = None
# https://github.com/opencv/opencv/blob/4.x/samples/cpp/stitching_detailed.cpp#L725 ?
for idx, name in enumerate(img_names):
full_img = cv.imread(name)
if not is_compose_scale_set:
if compose_megapix > 0:
compose_scale = min(1.0, np.sqrt(compose_megapix * 1e6 / (full_img.shape[0] * full_img.shape[1])))
is_compose_scale_set = True
compose_work_aspect = compose_scale / work_scale
warped_image_scale *= compose_work_aspect
warper = cv.PyRotationWarper(warp_type, warped_image_scale)
for i in range(0, len(img_names)):
cameras[i].focal *= compose_work_aspect
cameras[i].ppx *= compose_work_aspect
cameras[i].ppy *= compose_work_aspect
sz = (int(round(full_img_sizes[i][0] * compose_scale)),
int(round(full_img_sizes[i][1] * compose_scale)))
K = cameras[i].K().astype(np.float32)
roi = warper.warpRoi(sz, K, cameras[i].R)
corners.append(roi[0:2])
sizes.append(roi[2:4])
if abs(compose_scale - 1) > 1e-1:
img = cv.resize(src=full_img, dsize=None, fx=compose_scale, fy=compose_scale,
interpolation=cv.INTER_LINEAR_EXACT)
else:
img = full_img
_img_size = (img.shape[1], img.shape[0])
K = cameras[idx].K().astype(np.float32)
corner, image_warped = warper.warp(img, K, cameras[idx].R, cv.INTER_LINEAR, cv.BORDER_REFLECT)
mask = 255 * np.ones((img.shape[0], img.shape[1]), np.uint8)
p, mask_warped = warper.warp(mask, K, cameras[idx].R, cv.INTER_NEAREST, cv.BORDER_CONSTANT)
compensator.apply(idx, corners[idx], image_warped, mask_warped)
image_warped_s = image_warped.astype(np.int16)
dilated_mask = cv.dilate(masks_warped[idx], None)
seam_mask = cv.resize(dilated_mask, (mask_warped.shape[1], mask_warped.shape[0]), 0, 0, cv.INTER_LINEAR_EXACT)
mask_warped = cv.bitwise_and(seam_mask, mask_warped)
if blender is None and not timelapse:
blender = cv.detail.Blender_createDefault(cv.detail.Blender_NO)
dst_sz = cv.detail.resultRoi(corners=corners, sizes=sizes)
blend_width = np.sqrt(dst_sz[2] * dst_sz[3]) * blend_strength / 100
if blend_width < 1:
blender = cv.detail.Blender_createDefault(cv.detail.Blender_NO)
elif blend_type == "multiband":
blender = cv.detail_MultiBandBlender()
blender.setNumBands((np.log(blend_width) / np.log(2.) - 1.).astype(np.int32))
elif blend_type == "feather":
blender = cv.detail_FeatherBlender()
blender.setSharpness(1. / blend_width)
blender.prepare(dst_sz)
elif timelapser is None and timelapse:
timelapser = cv.detail.Timelapser_createDefault(timelapse_type)
timelapser.initialize(corners, sizes)
if timelapse:
ma_tones = np.ones((image_warped_s.shape[0], image_warped_s.shape[1]), np.uint8)
timelapser.process(image_warped_s, ma_tones, corners[idx])
pos_s = img_names[idx].rfind("/")
if pos_s == -1:
fixed_file_name = "fixed_" + img_names[idx]
else:
fixed_file_name = img_names[idx][:pos_s + 1] + "fixed_" + img_names[idx][pos_s + 1:]
cv.imwrite(fixed_file_name, timelapser.getDst())
else:
blender.feed(cv.UMat(image_warped_s), mask_warped, corners[idx])
if not timelapse:
result = None
result_mask = None
result, result_mask = blender.blend(result, result_mask)
cv.imwrite(result_name, result)
zoom_x = 600.0 / result.shape[1]
dst = cv.normalize(src=result, dst=None, alpha=255., norm_type=cv.NORM_MINMAX, dtype=cv.CV_8U)
dst = cv.resize(dst, dsize=None, fx=zoom_x, fy=zoom_x)
cv.imshow(result_name, dst)
cv.waitKey()
print("Done")
if __name__ == '__main__':
main()
cv.destroyAllWindows()
@@ -0,0 +1,60 @@
'''
Text skewness correction
This tutorial demonstrates how to correct the skewness in a text.
The program takes as input a skewed source image and shows non skewed text.
Usage:
python text_skewness_correction.py --image "Image path"
'''
import numpy as np
import cv2 as cv
import sys
import argparse
def main():
parser = argparse.ArgumentParser()
parser.add_argument("-i", "--image", default="imageTextR.png", help="path to input image file")
args = vars(parser.parse_args())
# load the image from disk
image = cv.imread(cv.samples.findFile(args["image"]))
if image is None:
print("can't read image " + args["image"])
sys.exit(-1)
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
# threshold the image, setting all foreground pixels to
# 255 and all background pixels to 0
thresh = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU)[1]
# Applying erode filter to remove random noise
erosion_size = 1
element = cv.getStructuringElement(cv.MORPH_RECT, (2 * erosion_size + 1, 2 * erosion_size + 1), (erosion_size, erosion_size) )
thresh = cv.erode(thresh, element)
coords = cv.findNonZero(thresh)
angle = cv.minAreaRect(coords)[-1]
# the `cv.minAreaRect` function returns values in the
# range [0, 90) if the angle is more than 45 we need to subtract 90 from it
if angle > 45:
angle = (angle - 90)
(h, w) = image.shape[:2]
center = (w // 2, h // 2)
M = cv.getRotationMatrix2D(center, angle, 1.0)
rotated = cv.warpAffine(image, M, (w, h), flags=cv.INTER_CUBIC, borderMode=cv.BORDER_REPLICATE)
cv.putText(rotated, "Angle: {:.2f} degrees".format(angle), (10, 30), cv.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
# show the output image
print("[INFO] angle: {:.2f}".format(angle))
cv.imshow("Input", image)
cv.imshow("Rotated", rotated)
cv.waitKey(0)
if __name__ == "__main__":
print(__doc__)
main()
cv.destroyAllWindows()
+55
View File
@@ -0,0 +1,55 @@
#!/usr/bin/env python
'''
Texture flow direction estimation.
Sample shows how cv.cornerEigenValsAndVecs function can be used
to estimate image texture flow direction.
Usage:
texture_flow.py [<image>]
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
def main():
import sys
try:
fn = sys.argv[1]
except:
fn = 'starry_night.jpg'
img = cv.imread(cv.samples.findFile(fn))
if img is None:
print('Failed to load image file:', fn)
sys.exit(1)
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
h, w = img.shape[:2]
eigen = cv.cornerEigenValsAndVecs(gray, 15, 3)
eigen = eigen.reshape(h, w, 3, 2) # [[e1, e2], v1, v2]
flow = eigen[:,:,2]
vis = img.copy()
vis[:] = (192 + np.uint32(vis)) / 2
d = 12
points = np.dstack( np.mgrid[d/2:w:d, d/2:h:d] ).reshape(-1, 2)
for x, y in np.int32(points):
vx, vy = np.int32(flow[y, x]*d)
cv.line(vis, (x-vx, y-vy), (x+vx, y+vy), (0, 0, 0), 1, cv.LINE_AA)
cv.imshow('input', img)
cv.imshow('flow', vis)
cv.waitKey()
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+181
View File
@@ -0,0 +1,181 @@
#!/usr/bin/env python
'''
Tracker demo
For usage download models by following links
For GOTURN:
goturn.prototxt and goturn.caffemodel: https://github.com/opencv/opencv_extra/tree/c4219d5eb3105ed8e634278fad312a1a8d2c182d/testdata/tracking
For DaSiamRPN:
network: https://www.dropbox.com/s/rr1lk9355vzolqv/dasiamrpn_model.onnx?dl=0
kernel_r1: https://www.dropbox.com/s/999cqx5zrfi7w4p/dasiamrpn_kernel_r1.onnx?dl=0
kernel_cls1: https://www.dropbox.com/s/qvmtszx5h339a0w/dasiamrpn_kernel_cls1.onnx?dl=0
For NanoTrack:
nanotrack_backbone: https://github.com/HonglinChu/SiamTrackers/blob/master/NanoTrack/models/nanotrackv2/nanotrack_backbone_sim.onnx
nanotrack_headneck: https://github.com/HonglinChu/SiamTrackers/blob/master/NanoTrack/models/nanotrackv2/nanotrack_head_sim.onnx
USAGE:
tracker.py [-h] [--input INPUT_VIDEO]
[--tracker_algo TRACKER_ALGO (mil, goturn, dasiamrpn, nanotrack, vittrack)]
[--goturn GOTURN_PROTOTXT]
[--goturn_model GOTURN_MODEL]
[--dasiamrpn_net DASIAMRPN_NET]
[--dasiamrpn_kernel_r1 DASIAMRPN_KERNEL_R1]
[--dasiamrpn_kernel_cls1 DASIAMRPN_KERNEL_CLS1]
[--nanotrack_backbone NANOTRACK_BACKBONE]
[--nanotrack_headneck NANOTRACK_TARGET]
[--vittrack_net VITTRACK_MODEL]
[--vittrack_net VITTRACK_MODEL]
[--tracking_score_threshold TRACKING SCORE THRESHOLD FOR ONLY VITTRACK]
[--backend CHOOSE ONE OF COMPUTATION BACKEND]
[--target CHOOSE ONE OF COMPUTATION TARGET]
'''
# Python 2/3 compatibility
from __future__ import print_function
import sys
import numpy as np
import cv2 as cv
import argparse
from video import create_capture, presets
backends = (cv.dnn.DNN_BACKEND_DEFAULT, cv.dnn.DNN_BACKEND_HALIDE, cv.dnn.DNN_BACKEND_INFERENCE_ENGINE, cv.dnn.DNN_BACKEND_OPENCV,
cv.dnn.DNN_BACKEND_VKCOM, cv.dnn.DNN_BACKEND_CUDA)
targets = (cv.dnn.DNN_TARGET_CPU, cv.dnn.DNN_TARGET_OPENCL, cv.dnn.DNN_TARGET_OPENCL_FP16, cv.dnn.DNN_TARGET_MYRIAD,
cv.dnn.DNN_TARGET_VULKAN, cv.dnn.DNN_TARGET_CUDA, cv.dnn.DNN_TARGET_CUDA_FP16)
class App(object):
def __init__(self, args):
self.args = args
self.trackerAlgorithm = args.tracker_algo
self.tracker = self.createTracker()
def createTracker(self):
if self.trackerAlgorithm == 'mil':
tracker = cv.TrackerMIL_create()
elif self.trackerAlgorithm == 'goturn':
params = cv.TrackerGOTURN_Params()
params.modelTxt = self.args.goturn
params.modelBin = self.args.goturn_model
tracker = cv.TrackerGOTURN_create(params)
elif self.trackerAlgorithm == 'dasiamrpn':
params = cv.TrackerDaSiamRPN_Params()
params.model = self.args.dasiamrpn_net
params.kernel_cls1 = self.args.dasiamrpn_kernel_cls1
params.kernel_r1 = self.args.dasiamrpn_kernel_r1
params.backend = args.backend
params.target = args.target
tracker = cv.TrackerDaSiamRPN_create(params)
elif self.trackerAlgorithm == 'nanotrack':
params = cv.TrackerNano_Params()
params.backbone = args.nanotrack_backbone
params.neckhead = args.nanotrack_headneck
params.backend = args.backend
params.target = args.target
tracker = cv.TrackerNano_create(params)
elif self.trackerAlgorithm == 'vittrack':
params = cv.TrackerVit_Params()
params.net = args.vittrack_net
params.tracking_score_threshold = args.tracking_score_threshold
params.backend = args.backend
params.target = args.target
tracker = cv.TrackerVit_create(params)
else:
sys.exit("Tracker {} is not recognized. Please use one of three available: mil, goturn, dasiamrpn, nanotrack.".format(self.trackerAlgorithm))
return tracker
def initializeTracker(self, image):
while True:
print('==> Select object ROI for tracker ...')
bbox = cv.selectROI('tracking', image)
print('ROI: {}'.format(bbox))
if bbox[2] <= 0 or bbox[3] <= 0:
sys.exit("ROI selection cancelled. Exiting...")
try:
self.tracker.init(image, bbox)
except Exception as e:
print('Unable to initialize tracker with requested bounding box. Is there any object?')
print(e)
print('Try again ...')
continue
return
def run(self):
videoPath = self.args.input
print('Using video: {}'.format(videoPath))
camera = create_capture(cv.samples.findFileOrKeep(videoPath), presets['cube'])
if not camera.isOpened():
sys.exit("Can't open video stream: {}".format(videoPath))
ok, image = camera.read()
if not ok:
sys.exit("Can't read first frame")
assert image is not None
cv.namedWindow('tracking')
self.initializeTracker(image)
print("==> Tracking is started. Press 'SPACE' to re-initialize tracker or 'ESC' for exit...")
while camera.isOpened():
ok, image = camera.read()
if not ok:
print("Can't read frame")
break
ok, newbox = self.tracker.update(image)
#print(ok, newbox)
if ok:
cv.rectangle(image, newbox, (200,0,0))
cv.imshow("tracking", image)
k = cv.waitKey(1)
if k == 32: # SPACE
self.initializeTracker(image)
if k == 27: # ESC
break
print('Done')
if __name__ == '__main__':
print(__doc__)
parser = argparse.ArgumentParser(description="Run tracker")
parser.add_argument("--input", type=str, default="vtest.avi", help="Path to video source")
parser.add_argument("--tracker_algo", type=str, default="nanotrack", help="One of available tracking algorithms: mil, goturn, dasiamrpn, nanotrack, vittrack")
parser.add_argument("--goturn", type=str, default="goturn.prototxt", help="Path to GOTURN architecture")
parser.add_argument("--goturn_model", type=str, default="goturn.caffemodel", help="Path to GOTERN model")
parser.add_argument("--dasiamrpn_net", type=str, default="dasiamrpn_model.onnx", help="Path to onnx model of DaSiamRPN net")
parser.add_argument("--dasiamrpn_kernel_r1", type=str, default="dasiamrpn_kernel_r1.onnx", help="Path to onnx model of DaSiamRPN kernel_r1")
parser.add_argument("--dasiamrpn_kernel_cls1", type=str, default="dasiamrpn_kernel_cls1.onnx", help="Path to onnx model of DaSiamRPN kernel_cls1")
parser.add_argument("--nanotrack_backbone", type=str, default="nanotrack_backbone_sim.onnx", help="Path to onnx model of NanoTrack backBone")
parser.add_argument("--nanotrack_headneck", type=str, default="nanotrack_head_sim.onnx", help="Path to onnx model of NanoTrack headNeck")
parser.add_argument("--vittrack_net", type=str, default="vitTracker.onnx", help="Path to onnx model of vittrack")
parser.add_argument('--tracking_score_threshold', type=float, help="Tracking score threshold. If a bbox of score >= 0.3, it is considered as found ")
parser.add_argument('--backend', choices=backends, default=cv.dnn.DNN_BACKEND_DEFAULT, type=int,
help="Choose one of computation backends: "
"%d: automatically (by default), "
"%d: Halide language (http://halide-lang.org/), "
"%d: Intel's Deep Learning Inference Engine (https://software.intel.com/openvino-toolkit), "
"%d: OpenCV implementation, "
"%d: VKCOM, "
"%d: CUDA"% backends)
parser.add_argument("--target", choices=targets, default=cv.dnn.DNN_TARGET_CPU, type=int,
help="Choose one of target computation devices: "
'%d: CPU target (by default), '
'%d: OpenCL, '
'%d: OpenCL fp16 (half-float precision), '
'%d: VPU, '
'%d: VULKAN, '
'%d: CUDA, '
'%d: CUDA fp16 (half-float preprocess)'% targets)
args = parser.parse_args()
App(args).run()
cv.destroyAllWindows()
+121
View File
@@ -0,0 +1,121 @@
#!/usr/bin/env python
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
from numpy import pi, sin, cos
defaultSize = 512
class TestSceneRender():
def __init__(self, bgImg = None, fgImg = None,
deformation = False, speed = 0.25, **params):
self.time = 0.0
self.timeStep = 1.0 / 30.0
self.foreground = fgImg
self.deformation = deformation
self.speed = speed
if bgImg is not None:
self.sceneBg = bgImg.copy()
else:
self.sceneBg = np.zeros((defaultSize, defaultSize,3), np.uint8)
self.w = self.sceneBg.shape[0]
self.h = self.sceneBg.shape[1]
if fgImg is not None:
self.foreground = fgImg.copy()
self.center = self.currentCenter = (int(self.w/2 - fgImg.shape[0]/2), int(self.h/2 - fgImg.shape[1]/2))
self.xAmpl = self.sceneBg.shape[0] - (self.center[0] + fgImg.shape[0])
self.yAmpl = self.sceneBg.shape[1] - (self.center[1] + fgImg.shape[1])
self.initialRect = np.array([ (self.h/2, self.w/2), (self.h/2, self.w/2 + self.w/10),
(self.h/2 + self.h/10, self.w/2 + self.w/10), (self.h/2 + self.h/10, self.w/2)]).astype(int)
self.currentRect = self.initialRect
def getXOffset(self, time):
return int( self.xAmpl*cos(time*self.speed))
def getYOffset(self, time):
return int(self.yAmpl*sin(time*self.speed))
def setInitialRect(self, rect):
self.initialRect = rect
def getRectInTime(self, time):
if self.foreground is not None:
tmp = np.array(self.center) + np.array((self.getXOffset(time), self.getYOffset(time)))
x0, y0 = tmp
x1, y1 = tmp + self.foreground.shape[0:2]
return np.array([y0, x0, y1, x1])
else:
x0, y0 = self.initialRect[0] + np.array((self.getXOffset(time), self.getYOffset(time)))
x1, y1 = self.initialRect[2] + np.array((self.getXOffset(time), self.getYOffset(time)))
return np.array([y0, x0, y1, x1])
def getCurrentRect(self):
if self.foreground is not None:
x0 = self.currentCenter[0]
y0 = self.currentCenter[1]
x1 = self.currentCenter[0] + self.foreground.shape[0]
y1 = self.currentCenter[1] + self.foreground.shape[1]
return np.array([y0, x0, y1, x1])
else:
x0, y0 = self.currentRect[0]
x1, y1 = self.currentRect[2]
return np.array([x0, y0, x1, y1])
def getNextFrame(self):
img = self.sceneBg.copy()
if self.foreground is not None:
self.currentCenter = (self.center[0] + self.getXOffset(self.time), self.center[1] + self.getYOffset(self.time))
img[self.currentCenter[0]:self.currentCenter[0]+self.foreground.shape[0],
self.currentCenter[1]:self.currentCenter[1]+self.foreground.shape[1]] = self.foreground
else:
self.currentRect = self.initialRect + int( 30*cos(self.time*self.speed) + 50*sin(self.time*self.speed))
if self.deformation:
self.currentRect[1:3] += int(self.h/20*cos(self.time))
cv.fillConvexPoly(img, self.currentRect, (0, 0, 255))
self.time += self.timeStep
return img
def resetTime(self):
self.time = 0.0
def main():
backGr = cv.imread(cv.samples.findFile('graf1.png'))
fgr = cv.imread(cv.samples.findFile('box.png'))
render = TestSceneRender(backGr, fgr)
while True:
img = render.getNextFrame()
cv.imshow('img', img)
ch = cv.waitKey(3)
if ch == 27:
break
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
+81
View File
@@ -0,0 +1,81 @@
#!/usr/bin/env python
'''
Multiscale Turing Patterns generator
====================================
Inspired by http://www.jonathanmccabe.com/Cyclic_Symmetric_Multi-Scale_Turing_Patterns.pdf
'''
# Python 2/3 compatibility
from __future__ import print_function
import sys
PY3 = sys.version_info[0] == 3
if PY3:
xrange = range
import numpy as np
import cv2 as cv
from common import draw_str
import getopt, sys
from itertools import count
help_message = '''
USAGE: turing.py [-o <output.avi>]
Press ESC to stop.
'''
def main():
print(help_message)
w, h = 512, 512
args, _args_list = getopt.getopt(sys.argv[1:], 'o:', [])
args = dict(args)
out = None
if '-o' in args:
fn = args['-o']
out = cv.VideoWriter(args['-o'], cv.VideoWriter_fourcc(*'DIB '), 30.0, (w, h), False)
print('writing %s ...' % fn)
a = np.zeros((h, w), np.float32)
cv.randu(a, np.array([0]), np.array([1]))
def process_scale(a_lods, lod):
d = a_lods[lod] - cv.pyrUp(a_lods[lod+1])
for _i in xrange(lod):
d = cv.pyrUp(d)
v = cv.GaussianBlur(d*d, (3, 3), 0)
return np.sign(d), v
scale_num = 6
for frame_i in count():
a_lods = [a]
for i in xrange(scale_num):
a_lods.append(cv.pyrDown(a_lods[-1]))
ms, vs = [], []
for i in xrange(1, scale_num):
m, v = process_scale(a_lods, i)
ms.append(m)
vs.append(v)
mi = np.argmin(vs, 0)
a += np.choose(mi, ms) * 0.025
a = (a-a.min()) / np.ptp(a)
if out:
out.write(a)
vis = a.copy()
draw_str(vis, (20, 20), 'frame %d' % frame_i)
cv.imshow('a', vis)
if cv.waitKey(5) == 27:
break
print('Done')
if __name__ == '__main__':
print(__doc__)
main()
cv.destroyAllWindows()
@@ -0,0 +1,71 @@
from __future__ import print_function
from __future__ import division
import cv2 as cv
import numpy as np
import argparse
def Hist_and_Backproj(val):
## [initialize]
bins = val
histSize = max(bins, 2)
ranges = [0, 180] # hue_range
## [initialize]
## [Get the Histogram and normalize it]
hist = cv.calcHist([hue], [0], None, [histSize], ranges, accumulate=False)
cv.normalize(hist, hist, alpha=0, beta=255, norm_type=cv.NORM_MINMAX)
## [Get the Histogram and normalize it]
## [Get Backprojection]
backproj = cv.calcBackProject([hue], [0], hist, ranges, scale=1)
## [Get Backprojection]
## [Draw the backproj]
cv.imshow('BackProj', backproj)
## [Draw the backproj]
## [Draw the histogram]
w = 400
h = 400
bin_w = int(round(w / histSize))
histImg = np.zeros((h, w, 3), dtype=np.uint8)
for i in range(bins):
cv.rectangle(histImg, (i*bin_w, h), ( (i+1)*bin_w, h - int(np.round( hist[i]*h/255.0 )) ), (0, 0, 255), cv.FILLED)
cv.imshow('Histogram', histImg)
## [Draw the histogram]
## [Read the image]
parser = argparse.ArgumentParser(description='Code for Back Projection tutorial.')
parser.add_argument('--input', help='Path to input image.', default='home.jpg')
args = parser.parse_args()
src = cv.imread(cv.samples.findFile(args.input))
if src is None:
print('Could not open or find the image:', args.input)
exit(0)
## [Read the image]
## [Transform it to HSV]
hsv = cv.cvtColor(src, cv.COLOR_BGR2HSV)
## [Transform it to HSV]
## [Use only the Hue value]
ch = (0, 0)
hue = np.empty(hsv.shape, hsv.dtype)
cv.mixChannels([hsv], [hue], ch)
## [Use only the Hue value]
## [Create Trackbar to enter the number of bins]
window_image = 'Source image'
cv.namedWindow(window_image)
bins = 25
cv.createTrackbar('* Hue bins: ', window_image, bins, 180, Hist_and_Backproj )
Hist_and_Backproj(bins)
## [Create Trackbar to enter the number of bins]
## [Show the image]
cv.imshow(window_image, src)
cv.waitKey()
## [Show the image]
@@ -0,0 +1,79 @@
from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse
low = 20
up = 20
def callback_low(val):
global low
low = val
def callback_up(val):
global up
up = val
def pickPoint(event, x, y, flags, param):
if event != cv.EVENT_LBUTTONDOWN:
return
# Fill and get the mask
seed = (x, y)
newMaskVal = 255
newVal = (120, 120, 120)
connectivity = 8
flags = connectivity + (newMaskVal << 8 ) + cv.FLOODFILL_FIXED_RANGE + cv.FLOODFILL_MASK_ONLY
mask2 = np.zeros((src.shape[0] + 2, src.shape[1] + 2), dtype=np.uint8)
print('low:', low, 'up:', up)
cv.floodFill(src, mask2, seed, newVal, (low, low, low), (up, up, up), flags)
mask = mask2[1:-1,1:-1]
cv.imshow('Mask', mask)
Hist_and_Backproj(mask)
def Hist_and_Backproj(mask):
h_bins = 30
s_bins = 32
histSize = [h_bins, s_bins]
h_range = [0, 180]
s_range = [0, 256]
ranges = h_range + s_range # Concat list
channels = [0, 1]
# Get the Histogram and normalize it
hist = cv.calcHist([hsv], channels, mask, histSize, ranges, accumulate=False)
cv.normalize(hist, hist, alpha=0, beta=255, norm_type=cv.NORM_MINMAX)
# Get Backprojection
backproj = cv.calcBackProject([hsv], channels, hist, ranges, scale=1)
# Draw the backproj
cv.imshow('BackProj', backproj)
# Read the image
parser = argparse.ArgumentParser(description='Code for Back Projection tutorial.')
parser.add_argument('--input', help='Path to input image.', default='home.jpg')
args = parser.parse_args()
src = cv.imread(cv.samples.findFile(args.input))
if src is None:
print('Could not open or find the image:', args.input)
exit(0)
# Transform it to HSV
hsv = cv.cvtColor(src, cv.COLOR_BGR2HSV)
# Show the image
window_image = 'Source image'
cv.namedWindow(window_image)
cv.imshow(window_image, src)
# Set Trackbars for floodfill thresholds
cv.createTrackbar('Low thresh', window_image, low, 255, callback_low)
cv.createTrackbar('High thresh', window_image, up, 255, callback_up)
# Set a Mouse Callback
cv.setMouseCallback(window_image, pickPoint)
cv.waitKey()
@@ -0,0 +1,71 @@
from __future__ import print_function
from __future__ import division
import cv2 as cv
import numpy as np
import argparse
## [Load image]
parser = argparse.ArgumentParser(description='Code for Histogram Calculation tutorial.')
parser.add_argument('--input', help='Path to input image.', default='lena.jpg')
args = parser.parse_args()
src = cv.imread(cv.samples.findFile(args.input))
if src is None:
print('Could not open or find the image:', args.input)
exit(0)
## [Load image]
## [Separate the image in 3 places ( B, G and R )]
bgr_planes = cv.split(src)
## [Separate the image in 3 places ( B, G and R )]
## [Establish the number of bins]
histSize = 256
## [Establish the number of bins]
## [Set the ranges ( for B,G,R) )]
histRange = (0, 256) # the upper boundary is exclusive
## [Set the ranges ( for B,G,R) )]
## [Set histogram param]
accumulate = False
## [Set histogram param]
## [Compute the histograms]
b_hist = cv.calcHist(bgr_planes, [0], None, [histSize], histRange, accumulate=accumulate)
g_hist = cv.calcHist(bgr_planes, [1], None, [histSize], histRange, accumulate=accumulate)
r_hist = cv.calcHist(bgr_planes, [2], None, [histSize], histRange, accumulate=accumulate)
## [Compute the histograms]
## [Draw the histograms for B, G and R]
hist_w = 512
hist_h = 400
bin_w = int(round( hist_w/histSize ))
histImage = np.zeros((hist_h, hist_w, 3), dtype=np.uint8)
## [Draw the histograms for B, G and R]
## [Normalize the result to ( 0, histImage.rows )]
cv.normalize(b_hist, b_hist, alpha=0, beta=hist_h, norm_type=cv.NORM_MINMAX)
cv.normalize(g_hist, g_hist, alpha=0, beta=hist_h, norm_type=cv.NORM_MINMAX)
cv.normalize(r_hist, r_hist, alpha=0, beta=hist_h, norm_type=cv.NORM_MINMAX)
## [Normalize the result to ( 0, histImage.rows )]
## [Draw for each channel]
for i in range(1, histSize):
cv.line(histImage, ( bin_w*(i-1), hist_h - int(b_hist[i-1]) ),
( bin_w*(i), hist_h - int(b_hist[i]) ),
( 255, 0, 0), thickness=2)
cv.line(histImage, ( bin_w*(i-1), hist_h - int(g_hist[i-1]) ),
( bin_w*(i), hist_h - int(g_hist[i]) ),
( 0, 255, 0), thickness=2)
cv.line(histImage, ( bin_w*(i-1), hist_h - int(r_hist[i-1]) ),
( bin_w*(i), hist_h - int(r_hist[i]) ),
( 0, 0, 255), thickness=2)
## [Draw for each channel]
## [Display]
cv.imshow('Source image', src)
cv.imshow('calcHist Demo', histImage)
cv.waitKey()
## [Display]
@@ -0,0 +1,69 @@
from __future__ import print_function
from __future__ import division
import cv2 as cv
import numpy as np
import argparse
## [Load three images with different environment settings]
parser = argparse.ArgumentParser(description='Code for Histogram Comparison tutorial.')
parser.add_argument('--input1', help='Path to input image 1.')
parser.add_argument('--input2', help='Path to input image 2.')
parser.add_argument('--input3', help='Path to input image 3.')
args = parser.parse_args()
src_base = cv.imread(args.input1)
src_test1 = cv.imread(args.input2)
src_test2 = cv.imread(args.input3)
if src_base is None or src_test1 is None or src_test2 is None:
print('Could not open or find the images!')
exit(0)
## [Load three images with different environment settings]
## [Convert to HSV]
hsv_base = cv.cvtColor(src_base, cv.COLOR_BGR2HSV)
hsv_test1 = cv.cvtColor(src_test1, cv.COLOR_BGR2HSV)
hsv_test2 = cv.cvtColor(src_test2, cv.COLOR_BGR2HSV)
## [Convert to HSV]
## [Convert to HSV half]
hsv_half_down = hsv_base[hsv_base.shape[0]//2:,:]
## [Convert to HSV half]
## [Using 50 bins for hue and 60 for saturation]
h_bins = 50
s_bins = 60
histSize = [h_bins, s_bins]
# hue varies from 0 to 179, saturation from 0 to 255
h_ranges = [0, 180]
s_ranges = [0, 256]
ranges = h_ranges + s_ranges # concat lists
# Use the 0-th and 1-st channels
channels = [0, 1]
## [Using 50 bins for hue and 60 for saturation]
## [Calculate the histograms for the HSV images]
hist_base = cv.calcHist([hsv_base], channels, None, histSize, ranges, accumulate=False)
cv.normalize(hist_base, hist_base, alpha=1, beta=0, norm_type=cv.NORM_L1)
hist_half_down = cv.calcHist([hsv_half_down], channels, None, histSize, ranges, accumulate=False)
cv.normalize(hist_half_down, hist_half_down, alpha=1, beta=0, norm_type=cv.NORM_L1)
hist_test1 = cv.calcHist([hsv_test1], channels, None, histSize, ranges, accumulate=False)
cv.normalize(hist_test1, hist_test1, alpha=1, beta=0, norm_type=cv.NORM_L1)
hist_test2 = cv.calcHist([hsv_test2], channels, None, histSize, ranges, accumulate=False)
cv.normalize(hist_test2, hist_test2, alpha=1, beta=0, norm_type=cv.NORM_L1)
## [Calculate the histograms for the HSV images]
## [Apply the histogram comparison methods]
for compare_method in range(6):
base_base = cv.compareHist(hist_base, hist_base, compare_method)
base_half = cv.compareHist(hist_base, hist_half_down, compare_method)
base_test1 = cv.compareHist(hist_base, hist_test1, compare_method)
base_test2 = cv.compareHist(hist_base, hist_test2, compare_method)
print('Method:', compare_method, 'Perfect, Base-Half, Base-Test(1), Base-Test(2) :',\
base_base, '/', base_half, '/', base_test1, '/', base_test2)
## [Apply the histogram comparison methods]
@@ -0,0 +1,31 @@
from __future__ import print_function
import cv2 as cv
import argparse
## [Load image]
parser = argparse.ArgumentParser(description='Code for Histogram Equalization tutorial.')
parser.add_argument('--input', help='Path to input image.', default='lena.jpg')
args = parser.parse_args()
src = cv.imread(cv.samples.findFile(args.input))
if src is None:
print('Could not open or find the image:', args.input)
exit(0)
## [Load image]
## [Convert to grayscale]
src = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
## [Convert to grayscale]
## [Apply Histogram Equalization]
dst = cv.equalizeHist(src)
## [Apply Histogram Equalization]
## [Display results]
cv.imshow('Source image', src)
cv.imshow('Equalized Image', dst)
## [Display results]
## [Wait until user exits the program]
cv.waitKey()
## [Wait until user exits the program]
@@ -0,0 +1,54 @@
"""
@file filter2D.py
@brief Sample code that shows how to implement your own linear filters by using filter2D function
"""
import sys
import cv2 as cv
import numpy as np
def main(argv):
window_name = 'filter2D Demo'
## [load]
imageName = argv[0] if len(argv) > 0 else 'lena.jpg'
# Loads an image
src = cv.imread(cv.samples.findFile(imageName), cv.IMREAD_COLOR)
# Check if image is loaded fine
if src is None:
print ('Error opening image!')
print ('Usage: filter2D.py [image_name -- default lena.jpg] \n')
return -1
## [load]
## [init_arguments]
# Initialize ddepth argument for the filter
ddepth = -1
## [init_arguments]
# Loop - Will filter the image with different kernel sizes each 0.5 seconds
ind = 0
while True:
## [update_kernel]
# Update kernel size for a normalized box filter
kernel_size = 3 + 2 * (ind % 5)
kernel = np.ones((kernel_size, kernel_size), dtype=np.float32)
kernel /= (kernel_size * kernel_size)
## [update_kernel]
## [apply_filter]
# Apply filter
dst = cv.filter2D(src, ddepth, kernel)
## [apply_filter]
cv.imshow(window_name, dst)
c = cv.waitKey(500)
if c == 27:
break
ind += 1
return 0
if __name__ == "__main__":
main(sys.argv[1:])
@@ -0,0 +1,59 @@
import sys
import cv2 as cv
import numpy as np
def main(argv):
## [load]
default_file = 'smarties.png'
filename = argv[0] if len(argv) > 0 else default_file
# Loads an image
src = cv.imread(cv.samples.findFile(filename), cv.IMREAD_COLOR)
# Check if image is loaded fine
if src is None:
print ('Error opening image!')
print ('Usage: hough_circle.py [image_name -- default ' + default_file + '] \n')
return -1
## [load]
## [convert_to_gray]
# Convert it to gray
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
## [convert_to_gray]
## [reduce_noise]
# Reduce the noise to avoid false circle detection
gray = cv.medianBlur(gray, 5)
## [reduce_noise]
## [houghcircles]
rows = gray.shape[0]
circles = cv.HoughCircles(gray, cv.HOUGH_GRADIENT, 1, rows / 8,
param1=100, param2=30,
minRadius=1, maxRadius=30)
## [houghcircles]
## [draw]
if circles is not None:
circles = np.uint16(np.around(circles))
for i in circles[0, :]:
center = (i[0], i[1])
# circle center
cv.circle(src, center, 1, (0, 100, 100), 3)
# circle outline
radius = i[2]
cv.circle(src, center, radius, (255, 0, 255), 3)
## [draw]
## [display]
cv.imshow("detected circles", src)
cv.waitKey(0)
## [display]
return 0
if __name__ == "__main__":
main(sys.argv[1:])
@@ -0,0 +1,79 @@
"""
@file hough_lines.py
@brief This program demonstrates line finding with the Hough transform
"""
import sys
import math
import cv2 as cv
import numpy as np
def main(argv):
## [load]
default_file = 'sudoku.png'
filename = argv[0] if len(argv) > 0 else default_file
# Loads an image
src = cv.imread(cv.samples.findFile(filename), cv.IMREAD_GRAYSCALE)
# Check if image is loaded fine
if src is None:
print ('Error opening image!')
print ('Usage: hough_lines.py [image_name -- default ' + default_file + '] \n')
return -1
## [load]
## [edge_detection]
# Edge detection
dst = cv.Canny(src, 50, 200, None, 3)
## [edge_detection]
# Copy edges to the images that will display the results in BGR
cdst = cv.cvtColor(dst, cv.COLOR_GRAY2BGR)
cdstP = np.copy(cdst)
## [hough_lines]
# Standard Hough Line Transform
lines = cv.HoughLines(dst, 1, np.pi / 180, 150, None, 0, 0)
## [hough_lines]
## [draw_lines]
# Draw the lines
if lines is not None:
for i in range(0, len(lines)):
rho = lines[i][0][0]
theta = lines[i][0][1]
a = math.cos(theta)
b = math.sin(theta)
x0 = a * rho
y0 = b * rho
pt1 = (int(x0 + 1000*(-b)), int(y0 + 1000*(a)))
pt2 = (int(x0 - 1000*(-b)), int(y0 - 1000*(a)))
cv.line(cdst, pt1, pt2, (0,0,255), 3, cv.LINE_AA)
## [draw_lines]
## [hough_lines_p]
# Probabilistic Line Transform
linesP = cv.HoughLinesP(dst, 1, np.pi / 180, 50, None, 50, 10)
## [hough_lines_p]
## [draw_lines_p]
# Draw the lines
if linesP is not None:
for i in range(0, len(linesP)):
l = linesP[i][0]
cv.line(cdstP, (l[0], l[1]), (l[2], l[3]), (0,0,255), 3, cv.LINE_AA)
## [draw_lines_p]
## [imshow]
# Show results
cv.imshow("Source", src)
cv.imshow("Detected Lines (in red) - Standard Hough Line Transform", cdst)
cv.imshow("Detected Lines (in red) - Probabilistic Line Transform", cdstP)
## [imshow]
## [exit]
# Wait and Exit
cv.waitKey()
return 0
## [exit]
if __name__ == "__main__":
main(sys.argv[1:])
@@ -0,0 +1,59 @@
"""
@file laplace_demo.py
@brief Sample code showing how to detect edges using the Laplace operator
"""
import sys
import cv2 as cv
def main(argv):
# [variables]
# Declare the variables we are going to use
ddepth = cv.CV_16S
kernel_size = 3
window_name = "Laplace Demo"
# [variables]
# [load]
imageName = argv[0] if len(argv) > 0 else 'lena.jpg'
src = cv.imread(cv.samples.findFile(imageName), cv.IMREAD_COLOR) # Load an image
# Check if image is loaded fine
if src is None:
print ('Error opening image')
print ('Program Arguments: [image_name -- default lena.jpg]')
return -1
# [load]
# [reduce_noise]
# Remove noise by blurring with a Gaussian filter
src = cv.GaussianBlur(src, (3, 3), 0)
# [reduce_noise]
# [convert_to_gray]
# Convert the image to grayscale
src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# [convert_to_gray]
# Create Window
cv.namedWindow(window_name, cv.WINDOW_AUTOSIZE)
# [laplacian]
# Apply Laplace function
dst = cv.Laplacian(src_gray, ddepth, ksize=kernel_size)
# [laplacian]
# [convert]
# converting back to uint8
abs_dst = cv.convertScaleAbs(dst)
# [convert]
# [display]
cv.imshow(window_name, abs_dst)
cv.waitKey(0)
# [display]
return 0
if __name__ == "__main__":
main(sys.argv[1:])
@@ -0,0 +1,69 @@
"""
@file copy_make_border.py
@brief Sample code that shows the functionality of copyMakeBorder
"""
import sys
from random import randint
import cv2 as cv
def main(argv):
## [variables]
# First we declare the variables we are going to use
borderType = cv.BORDER_CONSTANT
window_name = "copyMakeBorder Demo"
## [variables]
## [load]
imageName = argv[0] if len(argv) > 0 else 'lena.jpg'
# Loads an image
src = cv.imread(cv.samples.findFile(imageName), cv.IMREAD_COLOR)
# Check if image is loaded fine
if src is None:
print ('Error opening image!')
print ('Usage: copy_make_border.py [image_name -- default lena.jpg] \n')
return -1
## [load]
# Brief how-to for this program
print ('\n'
'\t copyMakeBorder Demo: \n'
' -------------------- \n'
' ** Press \'c\' to set the border to a random constant value \n'
' ** Press \'r\' to set the border to be replicated \n'
' ** Press \'ESC\' to exit the program ')
## [create_window]
cv.namedWindow(window_name, cv.WINDOW_AUTOSIZE)
## [create_window]
## [init_arguments]
# Initialize arguments for the filter
top = int(0.05 * src.shape[0]) # shape[0] = rows
bottom = top
left = int(0.05 * src.shape[1]) # shape[1] = cols
right = left
## [init_arguments]
while 1:
## [update_value]
value = [randint(0, 255), randint(0, 255), randint(0, 255)]
## [update_value]
## [copymakeborder]
dst = cv.copyMakeBorder(src, top, bottom, left, right, borderType, None, value)
## [copymakeborder]
## [display]
cv.imshow(window_name, dst)
## [display]
## [check_keypress]
c = cv.waitKey(500)
if c == 27:
break
elif c == 99: # 99 = ord('c')
borderType = cv.BORDER_CONSTANT
elif c == 114: # 114 = ord('r')
borderType = cv.BORDER_REPLICATE
## [check_keypress]
return 0
if __name__ == "__main__":
main(sys.argv[1:])
@@ -0,0 +1,74 @@
"""
@file sobel_demo.py
@brief Sample code using Sobel and/or Scharr OpenCV functions to make a simple Edge Detector
"""
import sys
import cv2 as cv
def main(argv):
## [variables]
# First we declare the variables we are going to use
window_name = ('Sobel Demo - Simple Edge Detector')
scale = 1
delta = 0
ddepth = cv.CV_16S
## [variables]
## [load]
# As usual we load our source image (src)
# Check number of arguments
if len(argv) < 1:
print ('Not enough parameters')
print ('Usage:\nmorph_lines_detection.py < path_to_image >')
return -1
# Load the image
src = cv.imread(argv[0], cv.IMREAD_COLOR)
# Check if image is loaded fine
if src is None:
print ('Error opening image: ' + argv[0])
return -1
## [load]
## [reduce_noise]
# Remove noise by blurring with a Gaussian filter ( kernel size = 3 )
src = cv.GaussianBlur(src, (3, 3), 0)
## [reduce_noise]
## [convert_to_gray]
# Convert the image to grayscale
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
## [convert_to_gray]
## [sobel]
# Gradient-X
# grad_x = cv.Scharr(gray,ddepth,1,0)
grad_x = cv.Sobel(gray, ddepth, 1, 0, ksize=3, scale=scale, delta=delta, borderType=cv.BORDER_DEFAULT)
# Gradient-Y
# grad_y = cv.Scharr(gray,ddepth,0,1)
grad_y = cv.Sobel(gray, ddepth, 0, 1, ksize=3, scale=scale, delta=delta, borderType=cv.BORDER_DEFAULT)
## [sobel]
## [convert]
# converting back to uint8
abs_grad_x = cv.convertScaleAbs(grad_x)
abs_grad_y = cv.convertScaleAbs(grad_y)
## [convert]
## [blend]
## Total Gradient (approximate)
grad = cv.addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0)
## [blend]
## [display]
cv.imshow(window_name, grad)
cv.waitKey(0)
## [display]
return 0
if __name__ == "__main__":
main(sys.argv[1:])
@@ -0,0 +1,34 @@
from __future__ import print_function
import cv2 as cv
import argparse
max_lowThreshold = 100
window_name = 'Edge Map'
title_trackbar = 'Min Threshold:'
ratio = 3
kernel_size = 3
def CannyThreshold(val):
low_threshold = val
img_blur = cv.blur(src_gray, (3,3))
detected_edges = cv.Canny(img_blur, low_threshold, low_threshold*ratio, kernel_size)
mask = detected_edges != 0
dst = src * (mask[:,:,None].astype(src.dtype))
cv.imshow(window_name, dst)
parser = argparse.ArgumentParser(description='Code for Canny Edge Detector tutorial.')
parser.add_argument('--input', help='Path to input image.', default='fruits.jpg')
args = parser.parse_args()
src = cv.imread(cv.samples.findFile(args.input))
if src is None:
print('Could not open or find the image: ', args.input)
exit(0)
src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
cv.namedWindow(window_name)
cv.createTrackbar(title_trackbar, window_name , 0, max_lowThreshold, CannyThreshold)
CannyThreshold(0)
cv.waitKey()
@@ -0,0 +1,139 @@
from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse
import random as rng
rng.seed(12345)
## [load_image]
# Load the image
parser = argparse.ArgumentParser(description='Code for Image Segmentation with Distance Transform and Watershed Algorithm.\
Sample code showing how to segment overlapping objects using Laplacian filtering, \
in addition to Watershed and Distance Transformation')
parser.add_argument('--input', help='Path to input image.', default='cards.png')
args = parser.parse_args()
src = cv.imread(cv.samples.findFile(args.input))
if src is None:
print('Could not open or find the image:', args.input)
exit(0)
# Show source image
cv.imshow('Source Image', src)
## [load_image]
## [black_bg]
# Change the background from white to black, since that will help later to extract
# better results during the use of Distance Transform
src[np.all(src == 255, axis=2)] = 0
# Show output image
cv.imshow('Black Background Image', src)
## [black_bg]
## [sharp]
# Create a kernel that we will use to sharpen our image
# an approximation of second derivative, a quite strong kernel
kernel = np.array([[1, 1, 1], [1, -8, 1], [1, 1, 1]], dtype=np.float32)
# do the laplacian filtering as it is
# well, we need to convert everything in something more deeper then CV_8U
# because the kernel has some negative values,
# and we can expect in general to have a Laplacian image with negative values
# BUT a 8bits unsigned int (the one we are working with) can contain values from 0 to 255
# so the possible negative number will be truncated
imgLaplacian = cv.filter2D(src, cv.CV_32F, kernel)
sharp = np.float32(src)
imgResult = sharp - imgLaplacian
# convert back to 8bits gray scale
imgResult = np.clip(imgResult, 0, 255)
imgResult = imgResult.astype('uint8')
imgLaplacian = np.clip(imgLaplacian, 0, 255)
imgLaplacian = np.uint8(imgLaplacian)
#cv.imshow('Laplace Filtered Image', imgLaplacian)
cv.imshow('New Sharped Image', imgResult)
## [sharp]
## [bin]
# Create binary image from source image
bw = cv.cvtColor(imgResult, cv.COLOR_BGR2GRAY)
_, bw = cv.threshold(bw, 40, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
cv.imshow('Binary Image', bw)
## [bin]
## [dist]
# Perform the distance transform algorithm
dist = cv.distanceTransform(bw, cv.DIST_L2, 3)
# Normalize the distance image for range = {0.0, 1.0}
# so we can visualize and threshold it
cv.normalize(dist, dist, 0, 1.0, cv.NORM_MINMAX)
cv.imshow('Distance Transform Image', dist)
## [dist]
## [peaks]
# Threshold to obtain the peaks
# This will be the markers for the foreground objects
_, dist = cv.threshold(dist, 0.4, 1.0, cv.THRESH_BINARY)
# Dilate a bit the dist image
kernel1 = np.ones((3,3), dtype=np.uint8)
dist = cv.dilate(dist, kernel1)
cv.imshow('Peaks', dist)
## [peaks]
## [seeds]
# Create the CV_8U version of the distance image
# It is needed for findContours()
dist_8u = dist.astype('uint8')
# Find total markers
contours, _ = cv.findContours(dist_8u, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
# Create the marker image for the watershed algorithm
markers = np.zeros(dist.shape, dtype=np.int32)
# Draw the foreground markers
for i in range(len(contours)):
cv.drawContours(markers, contours, i, (i+1), -1)
# Draw the background marker
cv.circle(markers, (5,5), 3, (255,255,255), -1)
markers_8u = (markers * 10).astype('uint8')
cv.imshow('Markers', markers_8u)
## [seeds]
## [watershed]
# Perform the watershed algorithm
cv.watershed(imgResult, markers)
#mark = np.zeros(markers.shape, dtype=np.uint8)
mark = markers.astype('uint8')
mark = cv.bitwise_not(mark)
# uncomment this if you want to see how the mark
# image looks like at that point
#cv.imshow('Markers_v2', mark)
# Generate random colors
colors = []
for contour in contours:
colors.append((rng.randint(0,256), rng.randint(0,256), rng.randint(0,256)))
# Create the result image
dst = np.zeros((markers.shape[0], markers.shape[1], 3), dtype=np.uint8)
# Fill labeled objects with random colors
for i in range(markers.shape[0]):
for j in range(markers.shape[1]):
index = markers[i,j]
if index > 0 and index <= len(contours):
dst[i,j,:] = colors[index-1]
# Visualize the final image
cv.imshow('Final Result', dst)
## [watershed]
cv.waitKey()
@@ -0,0 +1,65 @@
from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse
## [Update]
def update_map(ind, map_x, map_y):
if ind == 0:
for i in range(map_x.shape[0]):
for j in range(map_x.shape[1]):
if j > map_x.shape[1]*0.25 and j < map_x.shape[1]*0.75 and i > map_x.shape[0]*0.25 and i < map_x.shape[0]*0.75:
map_x[i,j] = 2 * (j-map_x.shape[1]*0.25) + 0.5
map_y[i,j] = 2 * (i-map_y.shape[0]*0.25) + 0.5
else:
map_x[i,j] = 0
map_y[i,j] = 0
elif ind == 1:
for i in range(map_x.shape[0]):
map_x[i,:] = [x for x in range(map_x.shape[1])]
for j in range(map_y.shape[1]):
map_y[:,j] = [map_y.shape[0]-y for y in range(map_y.shape[0])]
elif ind == 2:
for i in range(map_x.shape[0]):
map_x[i,:] = [map_x.shape[1]-x for x in range(map_x.shape[1])]
for j in range(map_y.shape[1]):
map_y[:,j] = [y for y in range(map_y.shape[0])]
elif ind == 3:
for i in range(map_x.shape[0]):
map_x[i,:] = [map_x.shape[1]-x for x in range(map_x.shape[1])]
for j in range(map_y.shape[1]):
map_y[:,j] = [map_y.shape[0]-y for y in range(map_y.shape[0])]
## [Update]
parser = argparse.ArgumentParser(description='Code for Remapping tutorial.')
parser.add_argument('--input', help='Path to input image.', default='chicky_512.png')
args = parser.parse_args()
## [Load]
src = cv.imread(cv.samples.findFile(args.input), cv.IMREAD_COLOR)
if src is None:
print('Could not open or find the image: ', args.input)
exit(0)
## [Load]
## [Create]
map_x = np.zeros((src.shape[0], src.shape[1]), dtype=np.float32)
map_y = np.zeros((src.shape[0], src.shape[1]), dtype=np.float32)
## [Create]
## [Window]
window_name = 'Remap demo'
cv.namedWindow(window_name)
## [Window]
## [Loop]
ind = 0
while True:
update_map(ind, map_x, map_y)
ind = (ind + 1) % 4
dst = cv.remap(src, map_x, map_y, cv.INTER_LINEAR)
cv.imshow(window_name, dst)
c = cv.waitKey(1000)
if c == 27:
break
## [Loop]
@@ -0,0 +1,54 @@
from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse
## [Load the image]
parser = argparse.ArgumentParser(description='Code for Affine Transformations tutorial.')
parser.add_argument('--input', help='Path to input image.', default='lena.jpg')
args = parser.parse_args()
src = cv.imread(cv.samples.findFile(args.input))
if src is None:
print('Could not open or find the image:', args.input)
exit(0)
## [Load the image]
## [Set your 3 points to calculate the Affine Transform]
srcTri = np.array( [[0, 0], [src.shape[1] - 1, 0], [0, src.shape[0] - 1]] ).astype(np.float32)
dstTri = np.array( [[0, src.shape[1]*0.33], [src.shape[1]*0.85, src.shape[0]*0.25], [src.shape[1]*0.15, src.shape[0]*0.7]] ).astype(np.float32)
## [Set your 3 points to calculate the Affine Transform]
## [Get the Affine Transform]
warp_mat = cv.getAffineTransform(srcTri, dstTri)
## [Get the Affine Transform]
## [Apply the Affine Transform just found to the src image]
warp_dst = cv.warpAffine(src, warp_mat, (src.shape[1], src.shape[0]))
## [Apply the Affine Transform just found to the src image]
# Rotating the image after Warp
## [Compute a rotation matrix with respect to the center of the image]
center = (warp_dst.shape[1]//2, warp_dst.shape[0]//2)
angle = -50
scale = 0.6
## [Compute a rotation matrix with respect to the center of the image]
## [Get the rotation matrix with the specifications above]
rot_mat = cv.getRotationMatrix2D( center, angle, scale )
## [Get the rotation matrix with the specifications above]
## [Rotate the warped image]
warp_rotate_dst = cv.warpAffine(warp_dst, rot_mat, (warp_dst.shape[1], warp_dst.shape[0]))
## [Rotate the warped image]
## [Show what you got]
cv.imshow('Source image', src)
cv.imshow('Warp', warp_dst)
cv.imshow('Warp + Rotate', warp_rotate_dst)
## [Show what you got]
## [Wait until user exits the program]
cv.waitKey()
## [Wait until user exits the program]
@@ -0,0 +1,82 @@
from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse
import random as rng
rng.seed(12345)
def thresh_callback(val):
threshold = val
## [Canny]
# Detect edges using Canny
canny_output = cv.Canny(src_gray, threshold, threshold * 2)
## [Canny]
## [findContours]
# Find contours
contours, _ = cv.findContours(canny_output, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
## [findContours]
## [allthework]
# Approximate contours to polygons + get bounding rects and circles
contours_poly = [None]*len(contours)
boundRect = [None]*len(contours)
centers = [None]*len(contours)
radius = [None]*len(contours)
for i, c in enumerate(contours):
contours_poly[i] = cv.approxPolyDP(c, 3, True)
boundRect[i] = cv.boundingRect(contours_poly[i])
centers[i], radius[i] = cv.minEnclosingCircle(contours_poly[i])
## [allthework]
## [zeroMat]
drawing = np.zeros((canny_output.shape[0], canny_output.shape[1], 3), dtype=np.uint8)
## [zeroMat]
## [forContour]
# Draw polygonal contour + bonding rects + circles
for i in range(len(contours)):
color = (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256))
cv.drawContours(drawing, contours_poly, i, color)
cv.rectangle(drawing, (int(boundRect[i][0]), int(boundRect[i][1])), \
(int(boundRect[i][0]+boundRect[i][2]), int(boundRect[i][1]+boundRect[i][3])), color, 2)
cv.circle(drawing, (int(centers[i][0]), int(centers[i][1])), int(radius[i]), color, 2)
## [forContour]
## [showDrawings]
# Show in a window
cv.imshow('Contours', drawing)
## [showDrawings]
## [setup]
# Load source image
parser = argparse.ArgumentParser(description='Code for Creating Bounding boxes and circles for contours tutorial.')
parser.add_argument('--input', help='Path to input image.', default='stuff.jpg')
args = parser.parse_args()
src = cv.imread(cv.samples.findFile(args.input))
if src is None:
print('Could not open or find the image:', args.input)
exit(0)
# Convert image to gray and blur it
src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
src_gray = cv.blur(src_gray, (3,3))
## [setup]
## [createWindow]
# Create Window
source_window = 'Source'
cv.namedWindow(source_window)
cv.imshow(source_window, src)
## [createWindow]
## [trackbar]
max_thresh = 255
thresh = 100 # initial threshold
cv.createTrackbar('Canny thresh:', source_window, thresh, max_thresh, thresh_callback)
thresh_callback(thresh)
## [trackbar]
cv.waitKey()
@@ -0,0 +1,82 @@
from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse
import random as rng
rng.seed(12345)
def thresh_callback(val):
threshold = val
## [Canny]
# Detect edges using Canny
canny_output = cv.Canny(src_gray, threshold, threshold * 2)
## [Canny]
## [findContours]
# Find contours
contours, _ = cv.findContours(canny_output, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
## [findContours]
# Find the rotated rectangles and ellipses for each contour
minRect = [None]*len(contours)
minEllipse = [None]*len(contours)
for i, c in enumerate(contours):
minRect[i] = cv.minAreaRect(c)
if c.shape[0] > 5:
minEllipse[i] = cv.fitEllipse(c)
# Draw contours + rotated rects + ellipses
## [zeroMat]
drawing = np.zeros((canny_output.shape[0], canny_output.shape[1], 3), dtype=np.uint8)
## [zeroMat]
## [forContour]
for i, c in enumerate(contours):
color = (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256))
# contour
cv.drawContours(drawing, contours, i, color)
# ellipse
if c.shape[0] > 5:
cv.ellipse(drawing, minEllipse[i], color, 2)
# rotated rectangle
box = cv.boxPoints(minRect[i])
box = np.intp(box) #np.intp: Integer used for indexing (same as C ssize_t; normally either int32 or int64)
cv.drawContours(drawing, [box], 0, color)
## [forContour]
## [showDrawings]
# Show in a window
cv.imshow('Contours', drawing)
## [showDrawings]
## [setup]
# Load source image
parser = argparse.ArgumentParser(description='Code for Creating Bounding rotated boxes and ellipses for contours tutorial.')
parser.add_argument('--input', help='Path to input image.', default='stuff.jpg')
args = parser.parse_args()
src = cv.imread(cv.samples.findFile(args.input))
if src is None:
print('Could not open or find the image:', args.input)
exit(0)
# Convert image to gray and blur it
src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
src_gray = cv.blur(src_gray, (3,3))
## [setup]
## [createWindow]
# Create Window
source_window = 'Source'
cv.namedWindow(source_window)
cv.imshow(source_window, src)
## [createWindow]
## [trackbar]
max_thresh = 255
thresh = 100 # initial threshold
cv.createTrackbar('Canny Thresh:', source_window, thresh, max_thresh, thresh_callback)
thresh_callback(thresh)
## [trackbar]
cv.waitKey()
@@ -0,0 +1,50 @@
from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse
import random as rng
rng.seed(12345)
def thresh_callback(val):
threshold = val
# Detect edges using Canny
canny_output = cv.Canny(src_gray, threshold, threshold * 2)
# Find contours
contours, hierarchy = cv.findContours(canny_output, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
# Draw contours
drawing = np.zeros((canny_output.shape[0], canny_output.shape[1], 3), dtype=np.uint8)
for i in range(len(contours)):
color = (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256))
cv.drawContours(drawing, contours, i, color, 2, cv.LINE_8, hierarchy, 0)
# Show in a window
cv.imshow('Contours', drawing)
# Load source image
parser = argparse.ArgumentParser(description='Code for Finding contours in your image tutorial.')
parser.add_argument('--input', help='Path to input image.', default='HappyFish.jpg')
args = parser.parse_args()
src = cv.imread(cv.samples.findFile(args.input))
if src is None:
print('Could not open or find the image:', args.input)
exit(0)
# Convert image to gray and blur it
src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
src_gray = cv.blur(src_gray, (3,3))
# Create Window
source_window = 'Source'
cv.namedWindow(source_window)
cv.imshow(source_window, src)
max_thresh = 255
thresh = 100 # initial threshold
cv.createTrackbar('Canny Thresh:', source_window, thresh, max_thresh, thresh_callback)
thresh_callback(thresh)
cv.waitKey()
@@ -0,0 +1,57 @@
from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse
import random as rng
rng.seed(12345)
def thresh_callback(val):
threshold = val
# Detect edges using Canny
canny_output = cv.Canny(src_gray, threshold, threshold * 2)
# Find contours
contours, _ = cv.findContours(canny_output, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
# Find the convex hull object for each contour
hull_list = []
for i in range(len(contours)):
hull = cv.convexHull(contours[i])
hull_list.append(hull)
# Draw contours + hull results
drawing = np.zeros((canny_output.shape[0], canny_output.shape[1], 3), dtype=np.uint8)
for i in range(len(contours)):
color = (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256))
cv.drawContours(drawing, contours, i, color)
cv.drawContours(drawing, hull_list, i, color)
# Show in a window
cv.imshow('Contours', drawing)
# Load source image
parser = argparse.ArgumentParser(description='Code for Convex Hull tutorial.')
parser.add_argument('--input', help='Path to input image.', default='stuff.jpg')
args = parser.parse_args()
src = cv.imread(cv.samples.findFile(args.input))
if src is None:
print('Could not open or find the image:', args.input)
exit(0)
# Convert image to gray and blur it
src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
src_gray = cv.blur(src_gray, (3,3))
# Create Window
source_window = 'Source'
cv.namedWindow(source_window)
cv.imshow(source_window, src)
max_thresh = 255
thresh = 100 # initial threshold
cv.createTrackbar('Canny thresh:', source_window, thresh, max_thresh, thresh_callback)
thresh_callback(thresh)
cv.waitKey()
@@ -0,0 +1,83 @@
from __future__ import print_function
from __future__ import division
import cv2 as cv
import numpy as np
import argparse
import random as rng
rng.seed(12345)
def thresh_callback(val):
threshold = val
## [Canny]
# Detect edges using Canny
canny_output = cv.Canny(src_gray, threshold, threshold * 2)
## [Canny]
## [findContours]
# Find contours
contours, _ = cv.findContours(canny_output, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
## [findContours]
# Get the moments
mu = [None]*len(contours)
for i in range(len(contours)):
mu[i] = cv.moments(contours[i])
# Get the mass centers
mc = [None]*len(contours)
for i in range(len(contours)):
# add 1e-5 to avoid division by zero
mc[i] = (mu[i]['m10'] / (mu[i]['m00'] + 1e-5), mu[i]['m01'] / (mu[i]['m00'] + 1e-5))
# Draw contours
## [zeroMat]
drawing = np.zeros((canny_output.shape[0], canny_output.shape[1], 3), dtype=np.uint8)
## [zeroMat]
## [forContour]
for i in range(len(contours)):
color = (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256))
cv.drawContours(drawing, contours, i, color, 2)
cv.circle(drawing, (int(mc[i][0]), int(mc[i][1])), 4, color, -1)
## [forContour]
## [showDrawings]
# Show in a window
cv.imshow('Contours', drawing)
## [showDrawings]
# Calculate the area with the moments 00 and compare with the result of the OpenCV function
for i in range(len(contours)):
print(' * Contour[%d] - Area (M_00) = %.2f - Area OpenCV: %.2f - Length: %.2f' % (i, mu[i]['m00'], cv.contourArea(contours[i]), cv.arcLength(contours[i], True)))
## [setup]
# Load source image
parser = argparse.ArgumentParser(description='Code for Image Moments tutorial.')
parser.add_argument('--input', help='Path to input image.', default='stuff.jpg')
args = parser.parse_args()
src = cv.imread(cv.samples.findFile(args.input))
if src is None:
print('Could not open or find the image:', args.input)
exit(0)
# Convert image to gray and blur it
src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
src_gray = cv.blur(src_gray, (3,3))
## [setup]
## [createWindow]
# Create Window
source_window = 'Source'
cv.namedWindow(source_window)
cv.imshow(source_window, src)
## [createWindow]
## [trackbar]
max_thresh = 255
thresh = 100 # initial threshold
cv.createTrackbar('Canny Thresh:', source_window, thresh, max_thresh, thresh_callback)
thresh_callback(thresh)
## [trackbar]
cv.waitKey()
@@ -0,0 +1,52 @@
from __future__ import print_function
from __future__ import division
import cv2 as cv
import numpy as np
# Create an image
r = 100
src = np.zeros((4*r, 4*r), dtype=np.uint8)
# Create a sequence of points to make a contour
vert = [None]*6
vert[0] = (3*r//2, int(1.34*r))
vert[1] = (1*r, 2*r)
vert[2] = (3*r//2, int(2.866*r))
vert[3] = (5*r//2, int(2.866*r))
vert[4] = (3*r, 2*r)
vert[5] = (5*r//2, int(1.34*r))
# Draw it in src
for i in range(6):
cv.line(src, vert[i], vert[(i+1)%6], ( 255 ), 3)
# Get the contours
contours, _ = cv.findContours(src, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
# Calculate the distances to the contour
raw_dist = np.empty(src.shape, dtype=np.float32)
for i in range(src.shape[0]):
for j in range(src.shape[1]):
raw_dist[i,j] = cv.pointPolygonTest(contours[0], (j,i), True)
minVal, maxVal, _, maxDistPt = cv.minMaxLoc(raw_dist)
minVal = abs(minVal)
maxVal = abs(maxVal)
# Depicting the distances graphically
drawing = np.zeros((src.shape[0], src.shape[1], 3), dtype=np.uint8)
for i in range(src.shape[0]):
for j in range(src.shape[1]):
if raw_dist[i,j] < 0:
drawing[i,j,0] = 255 - abs(raw_dist[i,j]) * 255 / minVal
elif raw_dist[i,j] > 0:
drawing[i,j,2] = 255 - raw_dist[i,j] * 255 / maxVal
else:
drawing[i,j,0] = 255
drawing[i,j,1] = 255
drawing[i,j,2] = 255
cv.circle(drawing,maxDistPt, int(maxVal),(255,255,255), 1, cv.LINE_8, 0)
cv.imshow('Source', src)
cv.imshow('Distance and inscribed circle', drawing)
cv.waitKey()
@@ -0,0 +1,70 @@
from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse
import random as rng
source_window = 'Image'
maxTrackbar = 25
rng.seed(12345)
def goodFeaturesToTrack_Demo(val):
maxCorners = max(val, 1)
# Parameters for Shi-Tomasi algorithm
qualityLevel = 0.01
minDistance = 10
blockSize = 3
gradientSize = 3
useHarrisDetector = False
k = 0.04
# Copy the source image
copy = np.copy(src)
# Apply corner detection
corners = cv.goodFeaturesToTrack(src_gray, maxCorners, qualityLevel, minDistance, None, \
blockSize=blockSize, gradientSize=gradientSize, useHarrisDetector=useHarrisDetector, k=k)
# Draw corners detected
print('** Number of corners detected:', corners.shape[0])
radius = 4
for i in range(corners.shape[0]):
cv.circle(copy, (int(corners[i,0,0]), int(corners[i,0,1])), radius, (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256)), cv.FILLED)
# Show what you got
cv.namedWindow(source_window)
cv.imshow(source_window, copy)
# Set the needed parameters to find the refined corners
winSize = (5, 5)
zeroZone = (-1, -1)
criteria = (cv.TERM_CRITERIA_EPS + cv.TermCriteria_COUNT, 40, 0.001)
# Calculate the refined corner locations
corners = cv.cornerSubPix(src_gray, corners, winSize, zeroZone, criteria)
# Write them down
for i in range(corners.shape[0]):
print(" -- Refined Corner [", i, "] (", corners[i,0,0], ",", corners[i,0,1], ")")
# Load source image and convert it to gray
parser = argparse.ArgumentParser(description='Code for Shi-Tomasi corner detector tutorial.')
parser.add_argument('--input', help='Path to input image.', default='pic3.png')
args = parser.parse_args()
src = cv.imread(cv.samples.findFile(args.input))
if src is None:
print('Could not open or find the image:', args.input)
exit(0)
src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# Create a window and a trackbar
cv.namedWindow(source_window)
maxCorners = 10 # initial threshold
cv.createTrackbar('Threshold: ', source_window, maxCorners, maxTrackbar, goodFeaturesToTrack_Demo)
cv.imshow(source_window, src)
goodFeaturesToTrack_Demo(maxCorners)
cv.waitKey()
@@ -0,0 +1,80 @@
from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse
import random as rng
myHarris_window = 'My Harris corner detector'
myShiTomasi_window = 'My Shi Tomasi corner detector'
myHarris_qualityLevel = 50
myShiTomasi_qualityLevel = 50
max_qualityLevel = 100
rng.seed(12345)
def myHarris_function(val):
myHarris_copy = np.copy(src)
myHarris_qualityLevel = max(val, 1)
for i in range(src_gray.shape[0]):
for j in range(src_gray.shape[1]):
if Mc[i,j] > myHarris_minVal + ( myHarris_maxVal - myHarris_minVal )*myHarris_qualityLevel/max_qualityLevel:
cv.circle(myHarris_copy, (j,i), 4, (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256)), cv.FILLED)
cv.imshow(myHarris_window, myHarris_copy)
def myShiTomasi_function(val):
myShiTomasi_copy = np.copy(src)
myShiTomasi_qualityLevel = max(val, 1)
for i in range(src_gray.shape[0]):
for j in range(src_gray.shape[1]):
if myShiTomasi_dst[i,j] > myShiTomasi_minVal + ( myShiTomasi_maxVal - myShiTomasi_minVal )*myShiTomasi_qualityLevel/max_qualityLevel:
cv.circle(myShiTomasi_copy, (j,i), 4, (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256)), cv.FILLED)
cv.imshow(myShiTomasi_window, myShiTomasi_copy)
# Load source image and convert it to gray
parser = argparse.ArgumentParser(description='Code for Creating your own corner detector tutorial.')
parser.add_argument('--input', help='Path to input image.', default='building.jpg')
args = parser.parse_args()
src = cv.imread(cv.samples.findFile(args.input))
if src is None:
print('Could not open or find the image:', args.input)
exit(0)
src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# Set some parameters
blockSize = 3
apertureSize = 3
# My Harris matrix -- Using cornerEigenValsAndVecs
myHarris_dst = cv.cornerEigenValsAndVecs(src_gray, blockSize, apertureSize)
# calculate Mc
Mc = np.empty(src_gray.shape, dtype=np.float32)
for i in range(src_gray.shape[0]):
for j in range(src_gray.shape[1]):
lambda_1 = myHarris_dst[i,j,0]
lambda_2 = myHarris_dst[i,j,1]
Mc[i,j] = lambda_1*lambda_2 - 0.04*pow( ( lambda_1 + lambda_2 ), 2 )
myHarris_minVal, myHarris_maxVal, _, _ = cv.minMaxLoc(Mc)
# Create Window and Trackbar
cv.namedWindow(myHarris_window)
cv.createTrackbar('Quality Level:', myHarris_window, myHarris_qualityLevel, max_qualityLevel, myHarris_function)
myHarris_function(myHarris_qualityLevel)
# My Shi-Tomasi -- Using cornerMinEigenVal
myShiTomasi_dst = cv.cornerMinEigenVal(src_gray, blockSize, apertureSize)
myShiTomasi_minVal, myShiTomasi_maxVal, _, _ = cv.minMaxLoc(myShiTomasi_dst)
# Create Window and Trackbar
cv.namedWindow(myShiTomasi_window)
cv.createTrackbar('Quality Level:', myShiTomasi_window, myShiTomasi_qualityLevel, max_qualityLevel, myShiTomasi_function)
myShiTomasi_function(myShiTomasi_qualityLevel)
cv.waitKey()
@@ -0,0 +1,58 @@
from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse
import random as rng
source_window = 'Image'
maxTrackbar = 100
rng.seed(12345)
def goodFeaturesToTrack_Demo(val):
maxCorners = max(val, 1)
# Parameters for Shi-Tomasi algorithm
qualityLevel = 0.01
minDistance = 10
blockSize = 3
gradientSize = 3
useHarrisDetector = False
k = 0.04
# Copy the source image
copy = np.copy(src)
# Apply corner detection
corners = cv.goodFeaturesToTrack(src_gray, maxCorners, qualityLevel, minDistance, None, \
blockSize=blockSize, gradientSize=gradientSize, useHarrisDetector=useHarrisDetector, k=k)
# Draw corners detected
print('** Number of corners detected:', corners.shape[0])
radius = 4
for i in range(corners.shape[0]):
cv.circle(copy, (int(corners[i,0,0]), int(corners[i,0,1])), radius, (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256)), cv.FILLED)
# Show what you got
cv.namedWindow(source_window)
cv.imshow(source_window, copy)
# Load source image and convert it to gray
parser = argparse.ArgumentParser(description='Code for Shi-Tomasi corner detector tutorial.')
parser.add_argument('--input', help='Path to input image.', default='pic3.png')
args = parser.parse_args()
src = cv.imread(cv.samples.findFile(args.input))
if src is None:
print('Could not open or find the image:', args.input)
exit(0)
src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# Create a window and a trackbar
cv.namedWindow(source_window)
maxCorners = 23 # initial threshold
cv.createTrackbar('Threshold: ', source_window, maxCorners, maxTrackbar, goodFeaturesToTrack_Demo)
cv.imshow(source_window, src)
goodFeaturesToTrack_Demo(maxCorners)
cv.waitKey()
@@ -0,0 +1,55 @@
from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse
source_window = 'Source image'
corners_window = 'Corners detected'
max_thresh = 255
def cornerHarris_demo(val):
thresh = val
# Detector parameters
blockSize = 2
apertureSize = 3
k = 0.04
# Detecting corners
dst = cv.cornerHarris(src_gray, blockSize, apertureSize, k)
# Normalizing
dst_norm = np.empty(dst.shape, dtype=np.float32)
cv.normalize(dst, dst_norm, alpha=0, beta=255, norm_type=cv.NORM_MINMAX)
dst_norm_scaled = cv.convertScaleAbs(dst_norm)
# Drawing a circle around corners
for i in range(dst_norm.shape[0]):
for j in range(dst_norm.shape[1]):
if int(dst_norm[i,j]) > thresh:
cv.circle(dst_norm_scaled, (j,i), 5, (0), 2)
# Showing the result
cv.namedWindow(corners_window)
cv.imshow(corners_window, dst_norm_scaled)
# Load source image and convert it to gray
parser = argparse.ArgumentParser(description='Code for Harris corner detector tutorial.')
parser.add_argument('--input', help='Path to input image.', default='building.jpg')
args = parser.parse_args()
src = cv.imread(cv.samples.findFile(args.input))
if src is None:
print('Could not open or find the image:', args.input)
exit(0)
src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# Create a window and a trackbar
cv.namedWindow(source_window)
thresh = 200 # initial threshold
cv.createTrackbar('Threshold: ', source_window, thresh, max_thresh, cornerHarris_demo)
cv.imshow(source_window, src)
cornerHarris_demo(thresh)
cv.waitKey()
@@ -0,0 +1,36 @@
from __future__ import print_function
import cv2 as cv
alpha = 0.5
try:
raw_input # Python 2
except NameError:
raw_input = input # Python 3
print(''' Simple Linear Blender
-----------------------
* Enter alpha [0.0-1.0]: ''')
input_alpha = float(raw_input().strip())
if 0 <= alpha <= 1:
alpha = input_alpha
# [load]
src1 = cv.imread(cv.samples.findFile('LinuxLogo.jpg'))
src2 = cv.imread(cv.samples.findFile('WindowsLogo.jpg'))
# [load]
if src1 is None:
print("Error loading src1")
exit(-1)
elif src2 is None:
print("Error loading src2")
exit(-1)
# [blend_images]
beta = (1.0 - alpha)
dst = cv.addWeighted(src1, alpha, src2, beta, 0.0)
# [blend_images]
# [display]
cv.imshow('dst', dst)
cv.waitKey(0)
# [display]
cv.destroyAllWindows()
@@ -0,0 +1,80 @@
from __future__ import print_function
import sys
import cv2 as cv
import numpy as np
def print_help():
print('''
This program demonstrated the use of the discrete Fourier transform (DFT).
The dft of an image is taken and it's power spectrum is displayed.
Usage:
discrete_fourier_transform.py [image_name -- default lena.jpg]''')
def main(argv):
print_help()
filename = argv[0] if len(argv) > 0 else 'lena.jpg'
I = cv.imread(cv.samples.findFile(filename), cv.IMREAD_GRAYSCALE)
if I is None:
print('Error opening image')
return -1
## [expand]
rows, cols = I.shape
m = cv.getOptimalDFTSize( rows )
n = cv.getOptimalDFTSize( cols )
padded = cv.copyMakeBorder(I, 0, m - rows, 0, n - cols, cv.BORDER_CONSTANT, value=[0, 0, 0])
## [expand]
## [complex_and_real]
planes = [np.float32(padded), np.zeros(padded.shape, np.float32)]
complexI = cv.merge(planes) # Add to the expanded another plane with zeros
## [complex_and_real]
## [dft]
cv.dft(complexI, complexI) # this way the result may fit in the source matrix
## [dft]
# compute the magnitude and switch to logarithmic scale
# = > log(1 + sqrt(Re(DFT(I)) ^ 2 + Im(DFT(I)) ^ 2))
## [magnitude]
cv.split(complexI, planes) # planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))
cv.magnitude(planes[0], planes[1], planes[0])# planes[0] = magnitude
magI = planes[0]
## [magnitude]
## [log]
matOfOnes = np.ones(magI.shape, dtype=magI.dtype)
cv.add(matOfOnes, magI, magI) # switch to logarithmic scale
cv.log(magI, magI)
## [log]
## [crop_rearrange]
magI_rows, magI_cols = magI.shape
# crop the spectrum, if it has an odd number of rows or columns
magI = magI[0:(magI_rows & -2), 0:(magI_cols & -2)]
cx = int(magI_rows/2)
cy = int(magI_cols/2)
q0 = magI[0:cx, 0:cy] # Top-Left - Create a ROI per quadrant
q1 = magI[cx:cx+cx, 0:cy] # Top-Right
q2 = magI[0:cx, cy:cy+cy] # Bottom-Left
q3 = magI[cx:cx+cx, cy:cy+cy] # Bottom-Right
tmp = np.copy(q0) # swap quadrants (Top-Left with Bottom-Right)
magI[0:cx, 0:cy] = q3
magI[cx:cx + cx, cy:cy + cy] = tmp
tmp = np.copy(q1) # swap quadrant (Top-Right with Bottom-Left)
magI[cx:cx + cx, 0:cy] = q2
magI[0:cx, cy:cy + cy] = tmp
## [crop_rearrange]
## [normalize]
cv.normalize(magI, magI, 0, 1, cv.NORM_MINMAX) # Transform the matrix with float values into a
## viewable image form(float between values 0 and 1).
## [normalize]
cv.imshow("Input Image" , I ) # Show the result
cv.imshow("spectrum magnitude", magI)
cv.waitKey()
if __name__ == "__main__":
main(sys.argv[1:])
@@ -0,0 +1,157 @@
from __future__ import print_function
import numpy as np
import cv2 as cv
import sys
def help(filename):
print (
'''
{0} shows the usage of the OpenCV serialization functionality. \n\n
usage:\n
python3 {0} [output file name] (default outputfile.yml.gz)\n\n
The output file may be XML (xml), YAML (yml/yaml), or JSON (json).\n
You can even compress it by specifying this in its extension like xml.gz yaml.gz etc...\n
With FileStorage you can serialize objects in OpenCV.\n\n
For example: - create a class and have it serialized\n
- use it to read and write matrices.\n
'''.format(filename)
)
class MyData:
A = 97
X = np.pi
name = 'mydata1234'
def __repr__(self):
s = '{ name = ' + self.name + ', X = ' + str(self.X)
s = s + ', A = ' + str(self.A) + '}'
return s
## [inside]
def write(self, fs, name):
fs.startWriteStruct(name, cv.FileNode_MAP|cv.FileNode_FLOW)
fs.write('A', self.A)
fs.write('X', self.X)
fs.write('name', self.name)
fs.endWriteStruct()
def read(self, node):
if (not node.empty()):
self.A = int(node.getNode('A').real())
self.X = node.getNode('X').real()
self.name = node.getNode('name').string()
else:
self.A = self.X = 0
self.name = ''
## [inside]
def main(argv):
if len(argv) != 2:
help(argv[0])
filename = 'outputfile.yml.gz'
else :
filename = argv[1]
# write
## [iomati]
R = np.eye(3,3)
T = np.zeros((3,1))
## [iomati]
## [customIOi]
m = MyData()
## [customIOi]
## [open]
s = cv.FileStorage(filename, cv.FileStorage_WRITE)
# or:
# s = cv.FileStorage()
# s.open(filename, cv.FileStorage_WRITE)
## [open]
## [writeNum]
s.write('iterationNr', 100)
## [writeNum]
## [writeStr]
s.startWriteStruct('strings', cv.FileNode_SEQ)
for elem in ['image1.jpg', 'Awesomeness', '../data/baboon.jpg']:
s.write('', elem)
s.endWriteStruct()
## [writeStr]
## [writeMap]
s.startWriteStruct('Mapping', cv.FileNode_MAP)
s.write('One', 1)
s.write('Two', 2)
s.endWriteStruct()
## [writeMap]
## [iomatw]
s.write('R_MAT', R)
s.write('T_MAT', T)
## [iomatw]
## [customIOw]
m.write(s, 'MyData')
## [customIOw]
## [close]
s.release()
## [close]
print ('Write operation to file:', filename, 'completed successfully.')
# read
print ('\nReading: ')
s = cv.FileStorage()
s.open(filename, cv.FileStorage_READ)
## [readNum]
n = s.getNode('iterationNr')
itNr = int(n.real())
## [readNum]
print (itNr)
if (not s.isOpened()):
print ('Failed to open ', filename, file=sys.stderr)
help(argv[0])
exit(1)
## [readStr]
n = s.getNode('strings')
if (not n.isSeq()):
print ('strings is not a sequence! FAIL', file=sys.stderr)
exit(1)
for i in range(n.size()):
print (n.at(i).string())
## [readStr]
## [readMap]
n = s.getNode('Mapping')
print ('Two',int(n.getNode('Two').real()),'; ')
print ('One',int(n.getNode('One').real()),'\n')
## [readMap]
## [iomat]
R = s.getNode('R_MAT').mat()
T = s.getNode('T_MAT').mat()
## [iomat]
## [customIO]
m.read(s.getNode('MyData'))
## [customIO]
print ('\nR =',R)
print ('T =',T,'\n')
print ('MyData =','\n',m,'\n')
## [nonexist]
print ('Attempt to read NonExisting (should initialize the data structure',
'with its default).')
m.read(s.getNode('NonExisting'))
print ('\nNonExisting =','\n',m)
## [nonexist]
print ('\nTip: Open up',filename,'with a text editor to see the serialized data.')
if __name__ == '__main__':
main(sys.argv)
@@ -0,0 +1,100 @@
from __future__ import print_function
import sys
import time
import numpy as np
import cv2 as cv
## [basic_method]
def is_grayscale(my_image):
return len(my_image.shape) < 3
def saturated(sum_value):
if sum_value > 255:
sum_value = 255
if sum_value < 0:
sum_value = 0
return sum_value
def sharpen(my_image):
if is_grayscale(my_image):
height, width = my_image.shape
else:
my_image = cv.cvtColor(my_image, cv.CV_8U)
height, width, n_channels = my_image.shape
result = np.zeros(my_image.shape, my_image.dtype)
## [basic_method_loop]
for j in range(1, height - 1):
for i in range(1, width - 1):
if is_grayscale(my_image):
sum_value = 5 * my_image[j, i] - my_image[j + 1, i] - my_image[j - 1, i] \
- my_image[j, i + 1] - my_image[j, i - 1]
result[j, i] = saturated(sum_value)
else:
for k in range(0, n_channels):
sum_value = 5 * my_image[j, i, k] - my_image[j + 1, i, k] \
- my_image[j - 1, i, k] - my_image[j, i + 1, k]\
- my_image[j, i - 1, k]
result[j, i, k] = saturated(sum_value)
## [basic_method_loop]
return result
## [basic_method]
def main(argv):
filename = 'lena.jpg'
img_codec = cv.IMREAD_COLOR
if argv:
filename = sys.argv[1]
if len(argv) >= 2 and sys.argv[2] == "G":
img_codec = cv.IMREAD_GRAYSCALE
src = cv.imread(cv.samples.findFile(filename), img_codec)
if src is None:
print("Can't open image [" + filename + "]")
print("Usage:")
print("mat_mask_operations.py [image_path -- default lena.jpg] [G -- grayscale]")
return -1
cv.namedWindow("Input", cv.WINDOW_AUTOSIZE)
cv.namedWindow("Output", cv.WINDOW_AUTOSIZE)
cv.imshow("Input", src)
t = round(time.time())
dst0 = sharpen(src)
t = (time.time() - t)
print("Hand written function time passed in seconds: %s" % t)
cv.imshow("Output", dst0)
cv.waitKey()
t = time.time()
## [kern]
kernel = np.array([[0, -1, 0],
[-1, 5, -1],
[0, -1, 0]], np.float32) # kernel should be floating point type
## [kern]
## [filter2D]
dst1 = cv.filter2D(src, -1, kernel)
# ddepth = -1, means destination image has depth same as input image
## [filter2D]
t = (time.time() - t)
print("Built-in filter2D time passed in seconds: %s" % t)
cv.imshow("Output", dst1)
cv.waitKey(0)
cv.destroyAllWindows()
return 0
if __name__ == "__main__":
main(sys.argv[1:])
@@ -0,0 +1,92 @@
from __future__ import division
import cv2 as cv
import numpy as np
# Snippet code for Operations with images tutorial (not intended to be run)
def load():
# Input/Output
filename = 'img.jpg'
## [Load an image from a file]
img = cv.imread(filename)
## [Load an image from a file]
## [Load an image from a file in grayscale]
img = cv.imread(filename, cv.IMREAD_GRAYSCALE)
## [Load an image from a file in grayscale]
## [Save image]
cv.imwrite(filename, img)
## [Save image]
def access_pixel():
# Accessing pixel intensity values
img = np.empty((4,4,3), np.uint8)
y = 0
x = 0
## [Pixel access 1]
_intensity = img[y,x]
## [Pixel access 1]
## [Pixel access 3]
_blue = img[y,x,0]
_green = img[y,x,1]
_red = img[y,x,2]
## [Pixel access 3]
## [Pixel access 5]
img[y,x] = 128
## [Pixel access 5]
def reference_counting():
# Memory management and reference counting
## [Reference counting 2]
img = cv.imread('image.jpg')
_img1 = np.copy(img)
## [Reference counting 2]
## [Reference counting 3]
img = cv.imread('image.jpg')
_sobelx = cv.Sobel(img, cv.CV_32F, 1, 0)
## [Reference counting 3]
def primitive_operations():
img = np.empty((4,4,3), np.uint8)
## [Set image to black]
img[:] = 0
## [Set image to black]
## [Select ROI]
_smallImg = img[10:110,10:110]
## [Select ROI]
## [BGR to Gray]
img = cv.imread('image.jpg')
_grey = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
## [BGR to Gray]
src = np.ones((4,4), np.uint8)
## [Convert to CV_32F]
_dst = src.astype(np.float32)
## [Convert to CV_32F]
def visualize_images():
## [imshow 1]
img = cv.imread('image.jpg')
cv.namedWindow('image', cv.WINDOW_AUTOSIZE)
cv.imshow('image', img)
cv.waitKey()
## [imshow 1]
## [imshow 2]
img = cv.imread('image.jpg')
grey = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
sobelx = cv.Sobel(grey, cv.CV_32F, 1, 0)
# find minimum and maximum intensities
minVal = np.amin(sobelx)
maxVal = np.amax(sobelx)
draw = cv.convertScaleAbs(sobelx, alpha=255.0/(maxVal - minVal), beta=-minVal * 255.0/(maxVal - minVal))
cv.namedWindow('image', cv.WINDOW_AUTOSIZE)
cv.imshow('image', draw)
cv.waitKey()
## [imshow 2]
@@ -0,0 +1,41 @@
import numpy as np
from ..accuracy_eval import SemSegmEvaluation
from ..utils import plot_acc
def test_segm_models(models_list, data_fetcher, eval_params, experiment_name, is_print_eval_params=True,
is_plot_acc=True):
if is_print_eval_params:
print(
"===== Running evaluation of the classification models with the following params:\n"
"\t0. val data location: {}\n"
"\t1. val data labels: {}\n"
"\t2. frame size: {}\n"
"\t3. batch size: {}\n"
"\t4. transform to RGB: {}\n"
"\t5. log file location: {}\n".format(
eval_params.imgs_segm_dir,
eval_params.img_cls_file,
eval_params.frame_size,
eval_params.batch_size,
eval_params.bgr_to_rgb,
eval_params.log
)
)
accuracy_evaluator = SemSegmEvaluation(eval_params.log, eval_params.img_cls_file, eval_params.batch_size)
accuracy_evaluator.process(models_list, data_fetcher)
accuracy_array = np.array(accuracy_evaluator.general_fw_accuracy)
print(
"===== End of processing. Accuracy results:\n"
"\t1. max accuracy (top-5) for the original model: {}\n"
"\t2. max accuracy (top-5) for the DNN model: {}\n".format(
max(accuracy_array[:, 0]),
max(accuracy_array[:, 1]),
)
)
if is_plot_acc:
plot_acc(accuracy_array, experiment_name)
@@ -0,0 +1,59 @@
from torchvision import models
from ..pytorch_model import (
PyTorchModelPreparer,
PyTorchModelProcessor,
PyTorchDnnModelProcessor
)
from ...common.utils import set_pytorch_env, create_parser
class PyTorchFcnResNet50(PyTorchModelPreparer):
def __init__(self, model_name, original_model):
super(PyTorchFcnResNet50, self).__init__(model_name, original_model)
def main():
parser = create_parser()
cmd_args = parser.parse_args()
set_pytorch_env()
# Test the base process of model retrieval
resnets = PyTorchFcnResNet50(
model_name="resnet50",
original_model=models.segmentation.fcn_resnet50(pretrained=True)
)
model_dict = resnets.get_prepared_models()
if cmd_args.is_evaluate:
from ...common.test_config import TestConfig
from ...common.accuracy_eval import PASCALDataFetch
from ...common.test.voc_segm_test import test_segm_models
eval_params = TestConfig()
model_names = list(model_dict.keys())
original_model_name = model_names[0]
dnn_model_name = model_names[1]
#img_dir, segm_dir, names_file, segm_cls_colors_file, preproc)
data_fetcher = PASCALDataFetch(
imgs_dir=eval_params.imgs_segm_dir,
frame_size=eval_params.frame_size,
bgr_to_rgb=eval_params.bgr_to_rgb,
)
test_segm_models(
[
PyTorchModelProcessor(model_dict[original_model_name], original_model_name),
PyTorchDnnModelProcessor(model_dict[dnn_model_name], dnn_model_name)
],
data_fetcher,
eval_params,
original_model_name
)
if __name__ == "__main__":
main()
@@ -0,0 +1,71 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
def basicPanoramaStitching(img1Path, img2Path):
img1 = cv.imread(cv.samples.findFile(img1Path))
img2 = cv.imread(cv.samples.findFile(img2Path))
# [camera-pose-from-Blender-at-location-1]
c1Mo = np.array([[0.9659258723258972, 0.2588190734386444, 0.0, 1.5529145002365112],
[ 0.08852133899927139, -0.3303661346435547, -0.9396926164627075, -0.10281121730804443],
[-0.24321036040782928, 0.9076734185218811, -0.342020183801651, 6.130080699920654],
[0, 0, 0, 1]],dtype=np.float64)
# [camera-pose-from-Blender-at-location-1]
# [camera-pose-from-Blender-at-location-2]
c2Mo = np.array([[0.9659258723258972, -0.2588190734386444, 0.0, -1.5529145002365112],
[-0.08852133899927139, -0.3303661346435547, -0.9396926164627075, -0.10281121730804443],
[0.24321036040782928, 0.9076734185218811, -0.342020183801651, 6.130080699920654],
[0, 0, 0, 1]],dtype=np.float64)
# [camera-pose-from-Blender-at-location-2]
# [camera-intrinsics-from-Blender]
cameraMatrix = np.array([[700.0, 0.0, 320.0], [0.0, 700.0, 240.0], [0, 0, 1]], dtype=np.float32)
# [camera-intrinsics-from-Blender]
# [extract-rotation]
R1 = c1Mo[0:3, 0:3]
R2 = c2Mo[0:3, 0:3]
#[extract-rotation]
# [compute-rotation-displacement]
R2 = R2.transpose()
R_2to1 = np.dot(R1,R2)
# [compute-rotation-displacement]
# [compute-homography]
H = cameraMatrix.dot(R_2to1).dot(np.linalg.inv(cameraMatrix))
H = H / H[2][2]
# [compute-homography]
# [stitch]
img_stitch = cv.warpPerspective(img2, H, (img2.shape[1]*2, img2.shape[0]))
img_stitch[0:img1.shape[0], 0:img1.shape[1]] = img1
# [stitch]
img_space = np.zeros((img1.shape[0],50,3), dtype=np.uint8)
img_compare = cv.hconcat([img1,img_space, img2])
cv.imshow("Final", img_compare)
cv.imshow("Panorama", img_stitch)
cv.waitKey(0)
def main():
import argparse
parser = argparse.ArgumentParser(description="Code for homography tutorial. Example 5: basic panorama stitching from a rotating camera.")
parser.add_argument("-I1","--image1", help = "path to first image", default="Blender_Suzanne1.jpg")
parser.add_argument("-I2","--image2", help = "path to second image", default="Blender_Suzanne2.jpg")
args = parser.parse_args()
print("Panorama Stitching Started")
basicPanoramaStitching(args.image1, args.image2)
print("Panorama Stitching Completed Successfully")
if __name__ == '__main__':
main()

Some files were not shown because too many files have changed in this diff Show More