vendor: OpenCV 5.0.0 snapshot at 40738fb16ceddb5fb3fea747585f7ce6abb0605b
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
# python binary files
|
||||
*.pyc
|
||||
__pycache__
|
||||
|
||||
# tmp files from examples
|
||||
/output
|
||||
*.dat
|
||||
out.ply
|
||||
svm_scores.npz
|
||||
unused_api.txt
|
||||
@@ -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()
|
||||
Executable
+29
@@ -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 ))
|
||||
Executable
+25
@@ -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)
|
||||
@@ -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()
|
||||
Executable
+168
@@ -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()
|
||||
@@ -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()
|
||||
Executable
+209
@@ -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
@@ -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()
|
||||
@@ -0,0 +1,185 @@
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
import argparse
|
||||
import sys
|
||||
import os
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
|
||||
from dnn.common import *
|
||||
|
||||
def get_args_parser(func_args):
|
||||
backends = ("default", "openvino", "opencv", "vkcom", "cuda", "webnn")
|
||||
targets = ("cpu", "opencl", "opencl_fp16", "vpu", "vulkan", "cuda", "cuda_fp16")
|
||||
|
||||
parser = argparse.ArgumentParser(add_help=False)
|
||||
parser.add_argument('--zoo', default=os.path.join(os.path.dirname(os.path.abspath(__file__)), '../dnn', 'models.yml'),
|
||||
help='An optional path to file with preprocessing parameters.')
|
||||
parser.add_argument('--input', default='mcc_ccm_test.jpg', help='Path to input image for computing CCM')
|
||||
parser.add_argument('--query', default='baboon.jpg', help='Path to query image to apply color correction')
|
||||
parser.add_argument('--ccm_file', help='Path to YAML file containing pre-computed CCM parameters')
|
||||
parser.add_argument('--chart_type', type=int, default=0,
|
||||
help='chartType: 0-Standard, 1-DigitalSG, 2-Vinyl, default:0')
|
||||
parser.add_argument('--num_charts', type=int, default=1,
|
||||
help='Maximum number of charts in the image')
|
||||
parser.add_argument('--backend', default="default", type=str, choices=backends,
|
||||
help="Choose one of computation backends: "
|
||||
"default: automatically (by default), "
|
||||
"openvino: Intel's Deep Learning Inference Engine (https://software.intel.com/openvino-toolkit), "
|
||||
"opencv: OpenCV implementation, "
|
||||
"vkcom: VKCOM, "
|
||||
"cuda: CUDA, "
|
||||
"webnn: WebNN")
|
||||
parser.add_argument('--target', default="cpu", type=str, choices=targets,
|
||||
help="Choose one of target computation devices: "
|
||||
"cpu: CPU target (by default), "
|
||||
"opencl: OpenCL, "
|
||||
"opencl_fp16: OpenCL fp16 (half-float precision), "
|
||||
"vpu: VPU, "
|
||||
"vulkan: Vulkan, "
|
||||
"cuda: CUDA, "
|
||||
"cuda_fp16: CUDA fp16 (half-float preprocess)")
|
||||
|
||||
args, _ = parser.parse_known_args()
|
||||
add_preproc_args(args.zoo, parser, 'mcc', 'mcc')
|
||||
parser = argparse.ArgumentParser(parents=[parser],
|
||||
description='''
|
||||
To run:
|
||||
Default (compute new CCM):
|
||||
python color_correction_model.py --input=path/to/your/input/image --query=path/to/query/image
|
||||
DNN model:
|
||||
python color_correction_model.py mcc --input=path/to/your/input/image --query=path/to/query/image
|
||||
Using pre-computed CCM:
|
||||
python color_correction_model.py --ccm_file=path/to/ccm_output.yaml --query=path/to/query/image
|
||||
|
||||
Model path can also be specified using --model argument. And config path can be specified using --config.
|
||||
''', formatter_class=argparse.RawTextHelpFormatter)
|
||||
return parser.parse_args(func_args)
|
||||
|
||||
def process_frame(frame, detector, num_charts):
|
||||
if not detector.process(frame, num_charts):
|
||||
return None
|
||||
|
||||
checkers = detector.getListColorChecker()
|
||||
src = checkers[0].getChartsRGB(False)
|
||||
|
||||
return src
|
||||
|
||||
def main(func_args=None):
|
||||
args = get_args_parser(func_args)
|
||||
|
||||
if not (0 <= args.chart_type <= 2):
|
||||
raise ValueError("chartType must be 0, 1, or 2")
|
||||
|
||||
# Validate arguments based on whether using pre-computed CCM
|
||||
if args.ccm_file:
|
||||
if not args.query:
|
||||
print("[ERROR] Query image path must be provided when using pre-computed CCM.")
|
||||
return -1
|
||||
else:
|
||||
if not args.input:
|
||||
print("[ERROR] Input image path must be provided when computing new CCM.")
|
||||
return -1
|
||||
|
||||
# Read query image
|
||||
query_image = None
|
||||
if args.query:
|
||||
query_image = cv.imread(findFile(args.query))
|
||||
if query_image is None:
|
||||
print("[ERROR] Unable to read query image.")
|
||||
return -1
|
||||
|
||||
if os.getenv('OPENCV_SAMPLES_DATA_PATH') is not None:
|
||||
try:
|
||||
args.model = findModel(args.model, args.sha1)
|
||||
args.config = findModel(args.config, args.config_sha1)
|
||||
except:
|
||||
print("[WARN] Model file not provided, using default detector. Pass model using --model and config using --config to use dnn based detector.\n\n")
|
||||
args.model = None
|
||||
args.config = None
|
||||
else:
|
||||
args.model = None
|
||||
args.config = None
|
||||
print("[WARN] Model file not provided, using default detector. Pass model using --model and config using --config to use dnn based detector. Or, set OPENCV_SAMPLES_DATA_PATH environment variable.\n\n")
|
||||
|
||||
# Create color correction model
|
||||
model = cv.ccm.ColorCorrectionModel()
|
||||
|
||||
if args.ccm_file:
|
||||
# Load CCM from YAML file
|
||||
fs = cv.FileStorage(args.ccm_file, cv.FileStorage_READ)
|
||||
if not fs.isOpened():
|
||||
print(f"[ERROR] Unable to open CCM file: {args.ccm_file}")
|
||||
return -1
|
||||
model.read(fs.getNode("ColorCorrectionModel"))
|
||||
fs.release()
|
||||
print(f"Loaded CCM from file: {args.ccm_file}")
|
||||
else:
|
||||
# Read input image for computing new CCM
|
||||
image = cv.imread(findFile(args.input))
|
||||
if image is None:
|
||||
print("[ERROR] Unable to read input image.")
|
||||
return -1
|
||||
|
||||
# Create color checker detector
|
||||
if args.model and args.config:
|
||||
# Load the DNN from TensorFlow model
|
||||
engine = cv.dnn.ENGINE_AUTO
|
||||
if args.backend != "default" or args.target != "cpu":
|
||||
engine = cv.dnn.ENGINE_CLASSIC
|
||||
net = cv.dnn.readNetFromTensorflow(args.model, args.config, engine)
|
||||
net.setPreferableBackend(get_backend_id(args.backend))
|
||||
net.setPreferableTarget(get_target_id(args.target))
|
||||
|
||||
detector = cv.mcc_CCheckerDetector.create(net)
|
||||
print("Detecting checkers using neural network.")
|
||||
else:
|
||||
detector = cv.mcc_CCheckerDetector.create()
|
||||
print("Detecting checkers using default method (no DNN).")
|
||||
|
||||
detector.setColorChartType(args.chart_type)
|
||||
|
||||
# Process image to detect color checker
|
||||
src = process_frame(image, detector, args.num_charts)
|
||||
if src is None:
|
||||
print("No chart detected in the input image!")
|
||||
return -1
|
||||
|
||||
print("Actual colors:", src)
|
||||
|
||||
# Convert to double and normalize
|
||||
src = src.astype(np.float64) / 255.0
|
||||
|
||||
# Create and configure color correction model
|
||||
model = cv.ccm.ColorCorrectionModel(src, cv.ccm.COLORCHECKER_MACBETH)
|
||||
model.setCcmType(cv.ccm.CCM_LINEAR)
|
||||
model.setDistance(cv.ccm.DISTANCE_CIE2000)
|
||||
model.setLinearization(cv.ccm.LINEARIZATION_GAMMA)
|
||||
model.setLinearizationGamma(2.2)
|
||||
|
||||
# Compute color correction matrix
|
||||
ccm = model.compute()
|
||||
print("Computed CCM Matrix:\n", ccm)
|
||||
print("Loss:", model.getLoss())
|
||||
|
||||
# Save model parameters to YAML file
|
||||
fs = cv.FileStorage("ccm_output.yaml", cv.FileStorage_WRITE)
|
||||
model.write(fs)
|
||||
fs.release()
|
||||
print("Model parameters saved to ccm_output.yaml")
|
||||
|
||||
# Set query image for correction if not provided
|
||||
if query_image is None:
|
||||
print("[WARN] No query image provided, applying color correction on input image")
|
||||
query_image = image.copy()
|
||||
|
||||
# Apply correction to query image
|
||||
calibrated_image = np.empty_like(query_image)
|
||||
model.correctImage(query_image, calibrated_image)
|
||||
|
||||
cv.imshow("Original Image", query_image)
|
||||
cv.imshow("Corrected Image", calibrated_image)
|
||||
cv.waitKey(0)
|
||||
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Executable
+224
@@ -0,0 +1,224 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
This module contains some common routines used by other samples.
|
||||
'''
|
||||
|
||||
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
|
||||
output = it.zip_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)
|
||||
img0 = next(imgs)
|
||||
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)
|
||||
Executable
+179
@@ -0,0 +1,179 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
Sample-launcher application.
|
||||
'''
|
||||
|
||||
import sys
|
||||
|
||||
# local modules
|
||||
from common import splitfn
|
||||
|
||||
# built-in modules
|
||||
import webbrowser
|
||||
from glob import glob
|
||||
from subprocess import Popen
|
||||
|
||||
import tkinter as tk
|
||||
from tkinter.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:
|
||||
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')
|
||||
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()
|
||||
@@ -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()
|
||||
@@ -0,0 +1,133 @@
|
||||
import numpy as np, cv2 as cv, time, sys, os
|
||||
|
||||
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
|
||||
color = [1.0, 0.0, 0.0]
|
||||
colors = np.tile(color, (obj_pts.shape[0], 1))
|
||||
obj_pts = np.concatenate((obj_pts, colors), axis=1)
|
||||
obj_pts= np.float32(obj_pts)
|
||||
|
||||
cv.viz3d.showPoints("window", "points", obj_pts)
|
||||
cv.viz3d.setGridVisible("window", True)
|
||||
|
||||
# save figures
|
||||
cv.imshow("matches", image1)
|
||||
cv.imwrite('matches_E.png', image1)
|
||||
|
||||
cv.waitKey(0)
|
||||
Executable
+88
@@ -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()
|
||||
@@ -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()
|
||||
Executable
+74
@@ -0,0 +1,74 @@
|
||||
#!/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
|
||||
'''
|
||||
|
||||
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 range(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 range(leveln):
|
||||
cv.createTrackbar('%d'%i, 'level control', 5, 50, nothing)
|
||||
|
||||
while True:
|
||||
_ret, frame = cap.read()
|
||||
|
||||
pyr = build_lappyr(frame, leveln)
|
||||
for i in range(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()
|
||||
@@ -0,0 +1,155 @@
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
import argparse
|
||||
import sys
|
||||
import os
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
|
||||
from dnn.common import *
|
||||
|
||||
def get_args_parser(func_args):
|
||||
backends = ("default", "openvino", "opencv", "vkcom", "cuda")
|
||||
targets = ("cpu", "opencl", "opencl_fp16", "ncs2_vpu", "hddl_vpu", "vulkan", "cuda", "cuda_fp16")
|
||||
|
||||
parser = argparse.ArgumentParser(add_help=False)
|
||||
parser.add_argument('--zoo', default=os.path.join(os.path.dirname(os.path.abspath(__file__)), '../dnn', 'models.yml'),
|
||||
help='An optional path to file with preprocessing parameters.')
|
||||
parser.add_argument('--input', help='Path to input image or video file. Skip this argument to capture frames from a camera.', default=0, required=False)
|
||||
parser.add_argument('--method', help='choose method: dexined or canny', default='canny', required=False)
|
||||
parser.add_argument('--chart_type', type=int, default=0,
|
||||
help='chartType: 0-Standard, 1-DigitalSG, 2-Vinyl, default:0')
|
||||
parser.add_argument('--num_charts', type=int, default=1,
|
||||
help='Maximum number of charts in the image')
|
||||
parser.add_argument('--backend', default="default", type=str, choices=backends,
|
||||
help="Choose one of computation backends: "
|
||||
"default: automatically (by default), "
|
||||
"openvino: Intel's Deep Learning Inference Engine (https://software.intel.com/openvino-toolkit), "
|
||||
"opencv: OpenCV implementation, "
|
||||
"vkcom: VKCOM, "
|
||||
"cuda: CUDA, "
|
||||
"webnn: WebNN")
|
||||
parser.add_argument('--target', default="cpu", type=str, choices=targets,
|
||||
help="Choose one of target computation devices: "
|
||||
"cpu: CPU target (by default), "
|
||||
"opencl: OpenCL, "
|
||||
"opencl_fp16: OpenCL fp16 (half-float precision), "
|
||||
"ncs2_vpu: NCS2 VPU, "
|
||||
"hddl_vpu: HDDL VPU, "
|
||||
"vulkan: Vulkan, "
|
||||
"cuda: CUDA, "
|
||||
"cuda_fp16: CUDA fp16 (half-float preprocess)")
|
||||
|
||||
args, _ = parser.parse_known_args()
|
||||
add_preproc_args(args.zoo, parser, 'mcc', 'mcc')
|
||||
parser = argparse.ArgumentParser(parents=[parser],
|
||||
description='''
|
||||
To run:
|
||||
Default:
|
||||
python macbeth_chart_detection.py --input=path/to/your/input/image/or/video (don't give --input flag if want to use device camera)
|
||||
DNN model:
|
||||
python macbeth_chart_detection.py mcc --input=path/to/your/input/image/or/video
|
||||
|
||||
Model path can also be specified using --model argument. And config path can be specified using --config.
|
||||
''', formatter_class=argparse.RawTextHelpFormatter)
|
||||
return parser.parse_args(func_args)
|
||||
|
||||
def process_frame(frame, detector, num_charts):
|
||||
image_copy = frame.copy()
|
||||
if not detector.process(frame, num_charts):
|
||||
return None, None
|
||||
|
||||
checkers = detector.getListColorChecker()
|
||||
detector.draw(checkers, frame)
|
||||
|
||||
src = checkers[0].getChartsRGB(False)
|
||||
tgt = detector.getRefColors()
|
||||
|
||||
cv.imshow("image result | Press ESC to quit", frame)
|
||||
cv.imshow("original", image_copy)
|
||||
|
||||
return src, tgt
|
||||
|
||||
def main(func_args=None):
|
||||
args = get_args_parser(func_args)
|
||||
|
||||
if not (0 <= args.chart_type <= 2):
|
||||
raise ValueError("chartType must be 0, 1, or 2")
|
||||
|
||||
if os.getenv('OPENCV_SAMPLES_DATA_PATH') is not None:
|
||||
try:
|
||||
args.model = findModel(args.model, args.sha1)
|
||||
args.config = findModel(args.config, args.config_sha1)
|
||||
except:
|
||||
print("[WARN] Model file not provided, using default detector. Pass model using --model and config using --config to use dnn based detector.\n\n")
|
||||
args.model = None
|
||||
args.config = None
|
||||
else:
|
||||
args.model = None
|
||||
args.config = None
|
||||
print("[WARN] Model file not provided, using default detector. Pass model using --model and config using --config to use dnn based detector. Or, set OPENCV_SAMPLES_DATA_PATH environment variable.\n\n")
|
||||
|
||||
if args.model and args.config:
|
||||
# Load the DNN from TensorFlow model
|
||||
engine = cv.dnn.ENGINE_AUTO
|
||||
if args.backend != "default" or args.target != "cpu":
|
||||
engine = cv.dnn.ENGINE_CLASSIC
|
||||
net = cv.dnn.readNetFromTensorflow(args.model, args.config, engine)
|
||||
net.setPreferableBackend(get_backend_id(args.backend))
|
||||
net.setPreferableTarget(get_target_id(args.target))
|
||||
|
||||
detector = cv.mcc_CCheckerDetector.create(net)
|
||||
print("Detecting checkers using neural network.")
|
||||
else:
|
||||
detector = cv.mcc_CCheckerDetector.create()
|
||||
print("Detecting checkers using default method (no DNN).")
|
||||
|
||||
detector.setColorChartType(args.chart_type)
|
||||
is_video = True
|
||||
|
||||
if args.input:
|
||||
image = cv.imread(findFile(args.input))
|
||||
if image is not None:
|
||||
is_video = False
|
||||
else:
|
||||
cap = cv.VideoCapture(findFile(args.input))
|
||||
else:
|
||||
cap = cv.VideoCapture(0)
|
||||
|
||||
if is_video:
|
||||
print("To print the actual colors and reference colors for current frame press SPACEBAR. To resume press SPACEBAR again")
|
||||
|
||||
while True:
|
||||
ret, frame = cap.read()
|
||||
if not ret:
|
||||
break
|
||||
|
||||
src, tgt = process_frame(frame, detector, args.num_charts)
|
||||
|
||||
key = cv.waitKey(10) & 0xFF
|
||||
if key == ord(' '):
|
||||
if src is None or tgt is None:
|
||||
print("No color chart detected!!")
|
||||
else:
|
||||
print("Actual colors: ", src)
|
||||
print("Reference colors: ", tgt)
|
||||
print("Press spacebar to resume.")
|
||||
|
||||
cv.waitKey(0)
|
||||
print("Resumed! Processing continues...")
|
||||
elif key == 27:
|
||||
exit(0)
|
||||
if src is not None or tgt is not None:
|
||||
print("Actual colors: ", src)
|
||||
print("Reference colors: ", tgt)
|
||||
else:
|
||||
src, tgt = process_frame(image, detector, args.num_charts)
|
||||
if src is None or tgt is None:
|
||||
print("No color chart detected!!")
|
||||
else:
|
||||
print("Actual colors: ", src)
|
||||
print("Reference colors: ", tgt)
|
||||
cv.waitKey(0)
|
||||
|
||||
cv.destroyAllWindows()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Executable
+89
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
Morphology operations.
|
||||
|
||||
Usage:
|
||||
morphology.py [<image>]
|
||||
|
||||
Keys:
|
||||
1 - change operation
|
||||
2 - change structure element shape
|
||||
ESC - exit
|
||||
'''
|
||||
|
||||
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'])
|
||||
|
||||
cur_mode = next(modes)
|
||||
cur_str_mode = next(str_modes)
|
||||
|
||||
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'):
|
||||
cur_mode = next(modes)
|
||||
if ch == ord('2'):
|
||||
cur_str_mode = next(str_modes)
|
||||
update()
|
||||
|
||||
print('Done')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(__doc__)
|
||||
main()
|
||||
cv.destroyAllWindows()
|
||||
Executable
+88
@@ -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()
|
||||
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
'--algo',
|
||||
help="""DEPTH - works with depth,
|
||||
RGB - works with images,
|
||||
RGB_DEPTH - works with all,
|
||||
SCALE - works with depth and calculate Rt with scale,
|
||||
default - runs all algos""",
|
||||
default="")
|
||||
parser.add_argument(
|
||||
'-src_d',
|
||||
'--source_depth_frame',
|
||||
default="")
|
||||
parser.add_argument(
|
||||
'-dst_d',
|
||||
'--destination_depth_frame',
|
||||
default="")
|
||||
parser.add_argument(
|
||||
'-src_rgb',
|
||||
'--source_rgb_frame',
|
||||
default="")
|
||||
parser.add_argument(
|
||||
'-dst_rgb',
|
||||
'--destination_rgb_frame',
|
||||
default="")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.algo == "RGB_DEPTH" or args.algo == "DEPTH" or args.algo == "":
|
||||
source_depth_frame = cv.samples.findFile(args.source_depth_frame)
|
||||
destination_depth_frame = cv.samples.findFile(args.destination_depth_frame)
|
||||
depth1 = cv.imread(source_depth_frame, cv.IMREAD_ANYDEPTH).astype(np.float32)
|
||||
depth2 = cv.imread(destination_depth_frame, cv.IMREAD_ANYDEPTH).astype(np.float32)
|
||||
|
||||
if args.algo == "RGB_DEPTH" or args.algo == "RGB" or args.algo == "":
|
||||
source_rgb_frame = cv.samples.findFile(args.source_rgb_frame)
|
||||
destination_rgb_frame = cv.samples.findFile(args.destination_rgb_frame)
|
||||
rgb1 = cv.imread(source_rgb_frame, cv.IMREAD_COLOR)
|
||||
rgb2 = cv.imread(destination_rgb_frame, cv.IMREAD_COLOR)
|
||||
|
||||
if args.algo == "DEPTH" or args.algo == "":
|
||||
odometry = cv.Odometry(cv.DEPTH)
|
||||
Rt = np.zeros((4, 4))
|
||||
odometry.compute(depth1, depth2, Rt)
|
||||
print("Rt:\n {}".format(Rt))
|
||||
if args.algo == "RGB" or args.algo == "":
|
||||
odometry = cv.Odometry(cv.RGB)
|
||||
Rt = np.zeros((4, 4))
|
||||
odometry.compute(rgb1, rgb2, Rt)
|
||||
print("Rt:\n {}".format(Rt))
|
||||
if args.algo == "RGB_DEPTH" or args.algo == "":
|
||||
odometry = cv.Odometry(cv.RGB_DEPTH)
|
||||
Rt = np.zeros((4, 4))
|
||||
odometry.compute(depth1, rgb1, depth2, rgb2, Rt)
|
||||
print("Rt:\n {}".format(Rt))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -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()
|
||||
Executable
+181
@@ -0,0 +1,181 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
Multitarget planar tracking
|
||||
==================
|
||||
|
||||
Example of using "features" 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.
|
||||
'''
|
||||
|
||||
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 range(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()
|
||||
@@ -0,0 +1,23 @@
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
|
||||
vertices, _ = cv.loadPointCloud("../data/teapot.obj")
|
||||
vertices = np.squeeze(vertices, axis=1)
|
||||
print(vertices)
|
||||
|
||||
color = [1.0, 1.0, 0.0]
|
||||
colors = np.tile(color, (vertices.shape[0], 1))
|
||||
obj_pts = np.concatenate((vertices, colors), axis=1)
|
||||
obj_pts= np.float32(obj_pts)
|
||||
|
||||
cv.viz3d.showPoints("window", "points", obj_pts)
|
||||
cv.viz3d.setGridVisible("window", True)
|
||||
|
||||
cv.waitKey(0)
|
||||
|
||||
vertices, indices = cv.loadMesh("../data/teapot.obj")
|
||||
vertices = np.squeeze(vertices, axis=1)
|
||||
|
||||
cv.viz3d.showMesh("window", "mesh", vertices, indices)
|
||||
|
||||
cv.waitKey(0)
|
||||
@@ -0,0 +1,253 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
This program detects the QR-codes using OpenCV Library.
|
||||
|
||||
Usage:
|
||||
qrcode.py
|
||||
'''
|
||||
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
|
||||
import argparse
|
||||
|
||||
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):
|
||||
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, (0, 255, 0), int(round(contour_radius)))
|
||||
tpl = cnt.reshape((-1, 2))
|
||||
for x in tuple(tpl.tolist()):
|
||||
color = (255, 0, 0)
|
||||
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)
|
||||
self.drawQRCodeContours(result, cnt)
|
||||
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()
|
||||
Executable
+120
@@ -0,0 +1,120 @@
|
||||
#!/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
|
||||
'''
|
||||
|
||||
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 range(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()
|
||||
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python3
|
||||
# This file is part of OpenCV project.
|
||||
# It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
# of this distribution and at http://opencv.org/license.html
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import cv2 as cv
|
||||
|
||||
USAGE = """\
|
||||
Chromatic Aberration Correction Sample
|
||||
Usage:
|
||||
chromatic_aberration_correction.py <input_image> <calibration_file> [--bayer <code>] [--output <path>]
|
||||
|
||||
Arguments:
|
||||
input_image Path to the input image. Can be:
|
||||
• a 3-channel BGR image, or
|
||||
• a 1-channel raw Bayer image (see bayer_pattern)
|
||||
calibration_file OpenCV YAML/XML file with chromatic aberration calibration:
|
||||
image_width, image_height, red_channel/coeffs_x, coeffs_y,
|
||||
blue_channel/coeffs_x, coeffs_y.
|
||||
output (optional) Path to save the corrected image. Default: corrected.png
|
||||
bayer (optional) integer code for demosaicing a 1-channel raw image
|
||||
If omitted or <0, input is assumed 3-channel BGR.
|
||||
|
||||
Example:
|
||||
python chromatic_aberration_correction.py input.png calib.yaml --bayer 46 --output corrected.png
|
||||
"""
|
||||
|
||||
def main(argv=None):
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Chromatic Aberration Correction Sample",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog=USAGE
|
||||
)
|
||||
parser.add_argument("input", help="Input image (BGR or Bayer)")
|
||||
parser.add_argument("calibration", help="Calibration file (YAML/XML)")
|
||||
parser.add_argument("--output", default="corrected.png", help="Output image file")
|
||||
parser.add_argument("--bayer", type=int, default=-1, help="Bayer pattern code for demosaic")
|
||||
parser.add_argument("--no-gui", action="store_true", help="Do not open image windows")
|
||||
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
img = cv.imread(args.input, cv.IMREAD_UNCHANGED)
|
||||
if img is None:
|
||||
print(f"ERROR: Could not load input image: {args.input}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
fs = cv.FileStorage(args.calibration, cv.FileStorage_READ)
|
||||
if not fs.isOpened():
|
||||
print(f"Could not calibration coefficients from {args.calibration}")
|
||||
return 1
|
||||
|
||||
try:
|
||||
coeffMat, size, degree = cv.loadChromaticAberrationParams(fs.root())
|
||||
corrected = cv.correctChromaticAberration(img, coeffMat, size, degree, args.bayer)
|
||||
|
||||
if corrected is None:
|
||||
print("ERROR: cv.correctChromaticAberration returned None", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if not args.no_gui:
|
||||
cv.namedWindow("Original", cv.WINDOW_AUTOSIZE)
|
||||
cv.namedWindow("Corrected", cv.WINDOW_AUTOSIZE)
|
||||
cv.imshow("Original", img)
|
||||
cv.imshow("Corrected", corrected)
|
||||
print("Press any key to continue...")
|
||||
cv.waitKey(0)
|
||||
cv.destroyAllWindows()
|
||||
|
||||
if not cv.imwrite(args.output, corrected):
|
||||
print(f"WARNING: Could not write output image: {args.output}", file=sys.stderr)
|
||||
else:
|
||||
print(f"Saved corrected image to: {args.output}")
|
||||
|
||||
except cv.error as e:
|
||||
print(f"OpenCV error: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Executable
+66
@@ -0,0 +1,66 @@
|
||||
#!/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
|
||||
'''
|
||||
|
||||
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 range(6):
|
||||
dx = int((i%2)*250 - 30)
|
||||
dy = int((i/2.)*150)
|
||||
|
||||
if i == 0:
|
||||
for j in range(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()
|
||||
Executable
+120
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
sample for discrete 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()
|
||||
Executable
+122
@@ -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()
|
||||
Executable
+78
@@ -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()
|
||||
Executable
+94
@@ -0,0 +1,94 @@
|
||||
#!/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
|
||||
'''
|
||||
|
||||
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())
|
||||
|
||||
cur_func_name = next(dist_func_names)
|
||||
|
||||
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
|
||||
cur_func_name = next(dist_func_names)
|
||||
if ch == 27:
|
||||
break
|
||||
|
||||
print('Done')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(__doc__)
|
||||
main()
|
||||
cv.destroyAllWindows()
|
||||
Executable
+49
@@ -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()
|
||||
Executable
+60
@@ -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()
|
||||
Executable
+98
@@ -0,0 +1,98 @@
|
||||
#!/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.
|
||||
"""
|
||||
|
||||
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 = -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()
|
||||
Executable
+55
@@ -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()
|
||||
@@ -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()
|
||||
Executable
+106
@@ -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()
|
||||
Executable
+56
@@ -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()
|
||||
Executable
+104
@@ -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()
|
||||
Executable
+55
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
Simple "Square Detector" program.
|
||||
|
||||
Loads several images sequentially and tries to find squares in each image.
|
||||
'''
|
||||
|
||||
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 range(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 range(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()
|
||||
@@ -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()
|
||||
Executable
+55
@@ -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()
|
||||
Executable
+85
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
Watershed segmentation
|
||||
=========
|
||||
|
||||
This program demonstrates the watershed segmentation algorithm
|
||||
in OpenCV: watershed().
|
||||
|
||||
Usage
|
||||
-----
|
||||
watershed.py [image filename]
|
||||
|
||||
Keys
|
||||
----
|
||||
1-7 - switch marker color
|
||||
SPACE - update segmentation
|
||||
r - reset
|
||||
a - toggle autoupdate
|
||||
ESC - exit
|
||||
|
||||
'''
|
||||
|
||||
|
||||
# Python 2/3 compatibility
|
||||
from __future__ import print_function
|
||||
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
from common import Sketcher
|
||||
|
||||
class App:
|
||||
def __init__(self, fn):
|
||||
self.img = cv.imread(fn)
|
||||
if self.img is None:
|
||||
raise Exception('Failed to load image file: %s' % fn)
|
||||
|
||||
h, w = self.img.shape[:2]
|
||||
self.markers = np.zeros((h, w), np.int32)
|
||||
self.markers_vis = self.img.copy()
|
||||
self.cur_marker = 1
|
||||
self.colors = np.int32( list(np.ndindex(2, 2, 2)) ) * 255
|
||||
|
||||
self.auto_update = True
|
||||
self.sketch = Sketcher('img', [self.markers_vis, self.markers], self.get_colors)
|
||||
|
||||
def get_colors(self):
|
||||
return list(map(int, self.colors[self.cur_marker])), self.cur_marker
|
||||
|
||||
def watershed(self):
|
||||
m = self.markers.copy()
|
||||
cv.watershed(self.img, m)
|
||||
overlay = self.colors[np.maximum(m, 0)]
|
||||
vis = cv.addWeighted(self.img, 0.5, overlay, 0.5, 0.0, dtype=cv.CV_8UC3)
|
||||
cv.imshow('watershed', vis)
|
||||
|
||||
def run(self):
|
||||
while cv.getWindowProperty('img', 0) != -1 or cv.getWindowProperty('watershed', 0) != -1:
|
||||
ch = cv.waitKey(50)
|
||||
if ch == 27:
|
||||
break
|
||||
if ch >= ord('1') and ch <= ord('7'):
|
||||
self.cur_marker = ch - ord('0')
|
||||
print('marker: ', self.cur_marker)
|
||||
if ch == ord(' ') or (self.sketch.dirty and self.auto_update):
|
||||
self.watershed()
|
||||
self.sketch.dirty = False
|
||||
if ch in [ord('a'), ord('A')]:
|
||||
self.auto_update = not self.auto_update
|
||||
print('auto_update if', ['off', 'on'][self.auto_update])
|
||||
if ch in [ord('r'), ord('R')]:
|
||||
self.markers[:] = 0
|
||||
self.markers_vis[:] = self.img
|
||||
self.sketch.show()
|
||||
cv.destroyAllWindows()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(__doc__)
|
||||
import sys
|
||||
try:
|
||||
fn = sys.argv[1]
|
||||
except:
|
||||
fn = 'fruits.jpg'
|
||||
App(cv.samples.findFile(fn)).run()
|
||||
Executable
+85
@@ -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()
|
||||
@@ -0,0 +1,521 @@
|
||||
"""
|
||||
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:
|
||||
cv.xfeatures2d_BRISK.create() # check if the function can be called
|
||||
FEATURES_FIND_CHOICES['brisk'] = cv.xfeatures2d_BRISK.create
|
||||
except AttributeError:
|
||||
print("BRISK not available")
|
||||
try:
|
||||
cv.xfeatures2d_AKAZE.create() # check if the function can be called
|
||||
FEATURES_FIND_CHOICES['akaze'] = cv.xfeatures2d_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
|
||||
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/5.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,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()
|
||||
+71
@@ -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]
|
||||
+79
@@ -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()
|
||||
+71
@@ -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]
|
||||
+69
@@ -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]
|
||||
+31
@@ -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]
|
||||
+82
@@ -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()
|
||||
+82
@@ -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()
|
||||
+52
@@ -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()
|
||||
+80
@@ -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()
|
||||
+58
@@ -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()
|
||||
+80
@@ -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)
|
||||
+59
@@ -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()
|
||||
+71
@@ -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()
|
||||
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Python 2/3 compatibility
|
||||
from __future__ import print_function
|
||||
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
import sys
|
||||
|
||||
|
||||
def randomColor():
|
||||
color = np.random.randint(0, 255,(1, 3))
|
||||
return color[0].tolist()
|
||||
|
||||
def perspectiveCorrection(img1Path, img2Path ,patternSize ):
|
||||
img1 = cv.imread(cv.samples.findFile(img1Path))
|
||||
img2 = cv.imread(cv.samples.findFile(img2Path))
|
||||
|
||||
# [find-corners]
|
||||
ret1, corners1 = cv.findChessboardCorners(img1, patternSize)
|
||||
ret2, corners2 = cv.findChessboardCorners(img2, patternSize)
|
||||
# [find-corners]
|
||||
|
||||
if not ret1 or not ret2:
|
||||
print("Error, cannot find the chessboard corners in both images.")
|
||||
sys.exit(-1)
|
||||
|
||||
# [estimate-homography]
|
||||
H, _ = cv.findHomography(corners1, corners2)
|
||||
print(H)
|
||||
# [estimate-homography]
|
||||
|
||||
# [warp-chessboard]
|
||||
img1_warp = cv.warpPerspective(img1, H, (img1.shape[1], img1.shape[0]))
|
||||
# [warp-chessboard]
|
||||
|
||||
img_draw_warp = cv.hconcat([img2, img1_warp])
|
||||
cv.imshow("Desired chessboard view / Warped source chessboard view", img_draw_warp )
|
||||
|
||||
corners1 = corners1.tolist()
|
||||
corners1 = [a[0] for a in corners1]
|
||||
|
||||
# [compute-transformed-corners]
|
||||
img_draw_matches = cv.hconcat([img1, img2])
|
||||
for i in range(len(corners1)):
|
||||
pt1 = np.array([corners1[i][0], corners1[i][1], 1])
|
||||
pt1 = pt1.reshape(3, 1)
|
||||
pt2 = np.dot(H, pt1)
|
||||
pt2 = pt2/pt2[2]
|
||||
end = (int(img1.shape[1] + pt2[0]), int(pt2[1]))
|
||||
cv.line(img_draw_matches, tuple([int(j) for j in corners1[i]]), end, randomColor(), 2)
|
||||
|
||||
cv.imshow("Draw matches", img_draw_matches)
|
||||
cv.waitKey(0)
|
||||
# [compute-transformed-corners]
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-I1', "--image1", help="Path to the first image", default="left02.jpg")
|
||||
parser.add_argument('-I2', "--image2", help="Path to the second image", default="left01.jpg")
|
||||
parser.add_argument('-H', "--height", help="Height of pattern size", default=6)
|
||||
parser.add_argument('-W', "--width", help="Width of pattern size", default=9)
|
||||
args = parser.parse_args()
|
||||
|
||||
img1Path = args.image1
|
||||
img2Path = args.image2
|
||||
h = args.height
|
||||
w = args.width
|
||||
perspectiveCorrection(img1Path, img2Path, (w, h))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,81 @@
|
||||
from __future__ import print_function
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
import argparse
|
||||
from math import sqrt
|
||||
|
||||
## [load]
|
||||
parser = argparse.ArgumentParser(description='Code for AKAZE local features matching tutorial.')
|
||||
parser.add_argument('--input1', help='Path to input image 1.', default='graf1.png')
|
||||
parser.add_argument('--input2', help='Path to input image 2.', default='graf3.png')
|
||||
parser.add_argument('--homography', help='Path to the homography matrix.', default='H1to3p.xml')
|
||||
args = parser.parse_args()
|
||||
|
||||
img1 = cv.imread(cv.samples.findFile(args.input1), cv.IMREAD_GRAYSCALE)
|
||||
img2 = cv.imread(cv.samples.findFile(args.input2), cv.IMREAD_GRAYSCALE)
|
||||
if img1 is None or img2 is None:
|
||||
print('Could not open or find the images!')
|
||||
exit(0)
|
||||
|
||||
fs = cv.FileStorage(cv.samples.findFile(args.homography), cv.FILE_STORAGE_READ)
|
||||
homography = fs.getFirstTopLevelNode().mat()
|
||||
## [load]
|
||||
|
||||
## [AKAZE]
|
||||
akaze = cv.xfeatures2d.AKAZE_create()
|
||||
kpts1, desc1 = akaze.detectAndCompute(img1, None)
|
||||
kpts2, desc2 = akaze.detectAndCompute(img2, None)
|
||||
## [AKAZE]
|
||||
|
||||
## [2-nn matching]
|
||||
matcher = cv.DescriptorMatcher_create(cv.DescriptorMatcher_BRUTEFORCE_HAMMING)
|
||||
nn_matches = matcher.knnMatch(desc1, desc2, 2)
|
||||
## [2-nn matching]
|
||||
|
||||
## [ratio test filtering]
|
||||
matched1 = []
|
||||
matched2 = []
|
||||
nn_match_ratio = 0.8 # Nearest neighbor matching ratio
|
||||
for m, n in nn_matches:
|
||||
if m.distance < nn_match_ratio * n.distance:
|
||||
matched1.append(kpts1[m.queryIdx])
|
||||
matched2.append(kpts2[m.trainIdx])
|
||||
## [ratio test filtering]
|
||||
|
||||
## [homography check]
|
||||
inliers1 = []
|
||||
inliers2 = []
|
||||
good_matches = []
|
||||
inlier_threshold = 2.5 # Distance threshold to identify inliers with homography check
|
||||
for i, m in enumerate(matched1):
|
||||
col = np.ones((3,1), dtype=np.float64)
|
||||
col[0:2,0] = m.pt
|
||||
|
||||
col = np.dot(homography, col)
|
||||
col /= col[2,0]
|
||||
dist = sqrt(pow(col[0,0] - matched2[i].pt[0], 2) +\
|
||||
pow(col[1,0] - matched2[i].pt[1], 2))
|
||||
|
||||
if dist < inlier_threshold:
|
||||
good_matches.append(cv.DMatch(len(inliers1), len(inliers2), 0))
|
||||
inliers1.append(matched1[i])
|
||||
inliers2.append(matched2[i])
|
||||
## [homography check]
|
||||
|
||||
## [draw final matches]
|
||||
res = np.empty((max(img1.shape[0], img2.shape[0]), img1.shape[1]+img2.shape[1], 3), dtype=np.uint8)
|
||||
cv.drawMatches(img1, inliers1, img2, inliers2, good_matches, res)
|
||||
cv.imwrite("akaze_result.png", res)
|
||||
|
||||
inlier_ratio = len(inliers1) / float(len(matched1))
|
||||
print('A-KAZE Matching Results')
|
||||
print('*******************************')
|
||||
print('# Keypoints 1: \t', len(kpts1))
|
||||
print('# Keypoints 2: \t', len(kpts2))
|
||||
print('# Matches: \t', len(matched1))
|
||||
print('# Inliers: \t', len(inliers1))
|
||||
print('# Inliers Ratio: \t', inlier_ratio)
|
||||
|
||||
cv.imshow('result', res)
|
||||
cv.waitKey()
|
||||
## [draw final matches]
|
||||
@@ -0,0 +1,35 @@
|
||||
from __future__ import print_function
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='Code for Feature Detection tutorial.')
|
||||
parser.add_argument('--input1', help='Path to input image 1.', default='box.png')
|
||||
parser.add_argument('--input2', help='Path to input image 2.', default='box_in_scene.png')
|
||||
args = parser.parse_args()
|
||||
|
||||
img1 = cv.imread(cv.samples.findFile(args.input1), cv.IMREAD_GRAYSCALE)
|
||||
img2 = cv.imread(cv.samples.findFile(args.input2), cv.IMREAD_GRAYSCALE)
|
||||
if img1 is None or img2 is None:
|
||||
print('Could not open or find the images!')
|
||||
exit(0)
|
||||
|
||||
#-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors
|
||||
minHessian = 400
|
||||
detector = cv.xfeatures2d_SURF.create(hessianThreshold=minHessian)
|
||||
keypoints1, descriptors1 = detector.detectAndCompute(img1, None)
|
||||
keypoints2, descriptors2 = detector.detectAndCompute(img2, None)
|
||||
|
||||
#-- Step 2: Matching descriptor vectors with a brute force matcher
|
||||
# Since SURF is a floating-point descriptor NORM_L2 is used
|
||||
matcher = cv.DescriptorMatcher_create(cv.DescriptorMatcher_BRUTEFORCE)
|
||||
matches = matcher.match(descriptors1, descriptors2)
|
||||
|
||||
#-- Draw matches
|
||||
img_matches = np.empty((max(img1.shape[0], img2.shape[0]), img1.shape[1]+img2.shape[1], 3), dtype=np.uint8)
|
||||
cv.drawMatches(img1, keypoints1, img2, keypoints2, matches, img_matches)
|
||||
|
||||
#-- Show detected matches
|
||||
cv.imshow('Matches', img_matches)
|
||||
|
||||
cv.waitKey()
|
||||
@@ -0,0 +1,27 @@
|
||||
from __future__ import print_function
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='Code for Feature Detection tutorial.')
|
||||
parser.add_argument('--input', help='Path to input image.', default='box.png')
|
||||
args = parser.parse_args()
|
||||
|
||||
src = cv.imread(cv.samples.findFile(args.input), cv.IMREAD_GRAYSCALE)
|
||||
if src is None:
|
||||
print('Could not open or find the image:', args.input)
|
||||
exit(0)
|
||||
|
||||
#-- Step 1: Detect the keypoints using SURF Detector
|
||||
minHessian = 400
|
||||
detector = cv.xfeatures2d_SURF.create(hessianThreshold=minHessian)
|
||||
keypoints = detector.detect(src)
|
||||
|
||||
#-- Draw keypoints
|
||||
img_keypoints = np.empty((src.shape[0], src.shape[1], 3), dtype=np.uint8)
|
||||
cv.drawKeypoints(src, keypoints, img_keypoints)
|
||||
|
||||
#-- Show detected (drawn) keypoints
|
||||
cv.imshow('SURF Keypoints', img_keypoints)
|
||||
|
||||
cv.waitKey()
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
from __future__ import print_function
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='Code for Feature Matching with FLANN tutorial.')
|
||||
parser.add_argument('--input1', help='Path to input image 1.', default='box.png')
|
||||
parser.add_argument('--input2', help='Path to input image 2.', default='box_in_scene.png')
|
||||
args = parser.parse_args()
|
||||
|
||||
img1 = cv.imread(cv.samples.findFile(args.input1), cv.IMREAD_GRAYSCALE)
|
||||
img2 = cv.imread(cv.samples.findFile(args.input2), cv.IMREAD_GRAYSCALE)
|
||||
if img1 is None or img2 is None:
|
||||
print('Could not open or find the images!')
|
||||
exit(0)
|
||||
|
||||
#-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors
|
||||
minHessian = 400
|
||||
detector = cv.xfeatures2d_SURF.create(hessianThreshold=minHessian)
|
||||
keypoints1, descriptors1 = detector.detectAndCompute(img1, None)
|
||||
keypoints2, descriptors2 = detector.detectAndCompute(img2, None)
|
||||
|
||||
#-- Step 2: Matching descriptor vectors with a FLANN based matcher
|
||||
# Since SURF is a floating-point descriptor NORM_L2 is used
|
||||
matcher = cv.DescriptorMatcher_create(cv.DescriptorMatcher_FLANNBASED)
|
||||
knn_matches = matcher.knnMatch(descriptors1, descriptors2, 2)
|
||||
|
||||
#-- Filter matches using the Lowe's ratio test
|
||||
ratio_thresh = 0.7
|
||||
good_matches = []
|
||||
for m,n in knn_matches:
|
||||
if m.distance < ratio_thresh * n.distance:
|
||||
good_matches.append(m)
|
||||
|
||||
#-- Draw matches
|
||||
img_matches = np.empty((max(img1.shape[0], img2.shape[0]), img1.shape[1]+img2.shape[1], 3), dtype=np.uint8)
|
||||
cv.drawMatches(img1, keypoints1, img2, keypoints2, good_matches, img_matches, flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
|
||||
|
||||
#-- Show detected matches
|
||||
cv.imshow('Good Matches', img_matches)
|
||||
|
||||
cv.waitKey()
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
from __future__ import print_function
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='Code for Feature Matching with FLANN tutorial.')
|
||||
parser.add_argument('--input1', help='Path to input image 1.', default='box.png')
|
||||
parser.add_argument('--input2', help='Path to input image 2.', default='box_in_scene.png')
|
||||
args = parser.parse_args()
|
||||
|
||||
img_object = cv.imread(cv.samples.findFile(args.input1), cv.IMREAD_GRAYSCALE)
|
||||
img_scene = cv.imread(cv.samples.findFile(args.input2), cv.IMREAD_GRAYSCALE)
|
||||
if img_object is None or img_scene is None:
|
||||
print('Could not open or find the images!')
|
||||
exit(0)
|
||||
|
||||
#-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors
|
||||
minHessian = 400
|
||||
detector = cv.xfeatures2d_SURF.create(hessianThreshold=minHessian)
|
||||
keypoints_obj, descriptors_obj = detector.detectAndCompute(img_object, None)
|
||||
keypoints_scene, descriptors_scene = detector.detectAndCompute(img_scene, None)
|
||||
|
||||
#-- Step 2: Matching descriptor vectors with a FLANN based matcher
|
||||
# Since SURF is a floating-point descriptor NORM_L2 is used
|
||||
matcher = cv.DescriptorMatcher_create(cv.DescriptorMatcher_FLANNBASED)
|
||||
knn_matches = matcher.knnMatch(descriptors_obj, descriptors_scene, 2)
|
||||
|
||||
#-- Filter matches using the Lowe's ratio test
|
||||
ratio_thresh = 0.75
|
||||
good_matches = []
|
||||
for m,n in knn_matches:
|
||||
if m.distance < ratio_thresh * n.distance:
|
||||
good_matches.append(m)
|
||||
|
||||
#-- Draw matches
|
||||
img_matches = np.empty((max(img_object.shape[0], img_scene.shape[0]), img_object.shape[1]+img_scene.shape[1], 3), dtype=np.uint8)
|
||||
cv.drawMatches(img_object, keypoints_obj, img_scene, keypoints_scene, good_matches, img_matches, flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
|
||||
|
||||
#-- Localize the object
|
||||
obj = np.empty((len(good_matches),2), dtype=np.float32)
|
||||
scene = np.empty((len(good_matches),2), dtype=np.float32)
|
||||
for i in range(len(good_matches)):
|
||||
#-- Get the keypoints from the good matches
|
||||
obj[i,0] = keypoints_obj[good_matches[i].queryIdx].pt[0]
|
||||
obj[i,1] = keypoints_obj[good_matches[i].queryIdx].pt[1]
|
||||
scene[i,0] = keypoints_scene[good_matches[i].trainIdx].pt[0]
|
||||
scene[i,1] = keypoints_scene[good_matches[i].trainIdx].pt[1]
|
||||
|
||||
H, _ = cv.findHomography(obj, scene, cv.RANSAC)
|
||||
|
||||
#-- Get the corners from the image_1 ( the object to be "detected" )
|
||||
obj_corners = np.empty((4,1,2), dtype=np.float32)
|
||||
obj_corners[0,0,0] = 0
|
||||
obj_corners[0,0,1] = 0
|
||||
obj_corners[1,0,0] = img_object.shape[1]
|
||||
obj_corners[1,0,1] = 0
|
||||
obj_corners[2,0,0] = img_object.shape[1]
|
||||
obj_corners[2,0,1] = img_object.shape[0]
|
||||
obj_corners[3,0,0] = 0
|
||||
obj_corners[3,0,1] = img_object.shape[0]
|
||||
|
||||
scene_corners = cv.perspectiveTransform(obj_corners, H)
|
||||
|
||||
#-- Draw lines between the corners (the mapped object in the scene - image_2 )
|
||||
cv.line(img_matches, (int(scene_corners[0,0,0] + img_object.shape[1]), int(scene_corners[0,0,1])),\
|
||||
(int(scene_corners[1,0,0] + img_object.shape[1]), int(scene_corners[1,0,1])), (0,255,0), 4)
|
||||
cv.line(img_matches, (int(scene_corners[1,0,0] + img_object.shape[1]), int(scene_corners[1,0,1])),\
|
||||
(int(scene_corners[2,0,0] + img_object.shape[1]), int(scene_corners[2,0,1])), (0,255,0), 4)
|
||||
cv.line(img_matches, (int(scene_corners[2,0,0] + img_object.shape[1]), int(scene_corners[2,0,1])),\
|
||||
(int(scene_corners[3,0,0] + img_object.shape[1]), int(scene_corners[3,0,1])), (0,255,0), 4)
|
||||
cv.line(img_matches, (int(scene_corners[3,0,0] + img_object.shape[1]), int(scene_corners[3,0,1])),\
|
||||
(int(scene_corners[0,0,0] + img_object.shape[1]), int(scene_corners[0,0,1])), (0,255,0), 4)
|
||||
|
||||
#-- Show detected matches
|
||||
cv.imshow('Good Matches & Object detection', img_matches)
|
||||
|
||||
cv.waitKey()
|
||||
@@ -0,0 +1,48 @@
|
||||
from __future__ import print_function
|
||||
from __future__ import division
|
||||
import cv2 as cv
|
||||
import argparse
|
||||
|
||||
alpha_slider_max = 100
|
||||
title_window = 'Linear Blend'
|
||||
|
||||
## [on_trackbar]
|
||||
def on_trackbar(val):
|
||||
alpha = val / alpha_slider_max
|
||||
beta = ( 1.0 - alpha )
|
||||
dst = cv.addWeighted(src1, alpha, src2, beta, 0.0)
|
||||
cv.imshow(title_window, dst)
|
||||
## [on_trackbar]
|
||||
|
||||
parser = argparse.ArgumentParser(description='Code for Adding a Trackbar to our applications tutorial.')
|
||||
parser.add_argument('--input1', help='Path to the first input image.', default='LinuxLogo.jpg')
|
||||
parser.add_argument('--input2', help='Path to the second input image.', default='WindowsLogo.jpg')
|
||||
args = parser.parse_args()
|
||||
|
||||
## [load]
|
||||
# Read images ( both have to be of the same size and type )
|
||||
src1 = cv.imread(cv.samples.findFile(args.input1))
|
||||
src2 = cv.imread(cv.samples.findFile(args.input2))
|
||||
## [load]
|
||||
if src1 is None:
|
||||
print('Could not open or find the image: ', args.input1)
|
||||
exit(0)
|
||||
|
||||
if src2 is None:
|
||||
print('Could not open or find the image: ', args.input2)
|
||||
exit(0)
|
||||
|
||||
## [window]
|
||||
cv.namedWindow(title_window)
|
||||
## [window]
|
||||
|
||||
## [create_trackbar]
|
||||
trackbar_name = 'Alpha x %d' % alpha_slider_max
|
||||
cv.createTrackbar(trackbar_name, title_window , 0, alpha_slider_max, on_trackbar)
|
||||
## [create_trackbar]
|
||||
|
||||
# Show some stuff
|
||||
on_trackbar(0)
|
||||
|
||||
# Wait until user press some key
|
||||
cv.waitKey()
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
|
||||
W = 400
|
||||
## [my_ellipse]
|
||||
def my_ellipse(img, angle):
|
||||
thickness = 2
|
||||
line_type = 8
|
||||
|
||||
cv.ellipse(img,
|
||||
(W // 2, W // 2),
|
||||
(W // 4, W // 16),
|
||||
angle,
|
||||
0,
|
||||
360,
|
||||
(255, 0, 0),
|
||||
thickness,
|
||||
line_type)
|
||||
## [my_ellipse]
|
||||
## [my_filled_circle]
|
||||
def my_filled_circle(img, center):
|
||||
thickness = -1
|
||||
line_type = 8
|
||||
|
||||
cv.circle(img,
|
||||
center,
|
||||
W // 32,
|
||||
(0, 0, 255),
|
||||
thickness,
|
||||
line_type)
|
||||
## [my_filled_circle]
|
||||
## [my_polygon]
|
||||
def my_polygon(img):
|
||||
line_type = 8
|
||||
|
||||
# Create some points
|
||||
ppt = np.array([[W / 4, 7 * W / 8], [3 * W / 4, 7 * W / 8],
|
||||
[3 * W / 4, 13 * W / 16], [11 * W / 16, 13 * W / 16],
|
||||
[19 * W / 32, 3 * W / 8], [3 * W / 4, 3 * W / 8],
|
||||
[3 * W / 4, W / 8], [26 * W / 40, W / 8],
|
||||
[26 * W / 40, W / 4], [22 * W / 40, W / 4],
|
||||
[22 * W / 40, W / 8], [18 * W / 40, W / 8],
|
||||
[18 * W / 40, W / 4], [14 * W / 40, W / 4],
|
||||
[14 * W / 40, W / 8], [W / 4, W / 8],
|
||||
[W / 4, 3 * W / 8], [13 * W / 32, 3 * W / 8],
|
||||
[5 * W / 16, 13 * W / 16], [W / 4, 13 * W / 16]], np.int32)
|
||||
ppt = ppt.reshape((-1, 1, 2))
|
||||
cv.fillPoly(img, [ppt], (255, 255, 255), line_type)
|
||||
# Only drawind the lines would be:
|
||||
# cv.polylines(img, [ppt], True, (255, 0, 255), line_type)
|
||||
## [my_polygon]
|
||||
## [my_line]
|
||||
def my_line(img, start, end):
|
||||
thickness = 2
|
||||
line_type = 8
|
||||
|
||||
cv.line(img,
|
||||
start,
|
||||
end,
|
||||
(0, 0, 0),
|
||||
thickness,
|
||||
line_type)
|
||||
## [my_line]
|
||||
## [create_images]
|
||||
# Windows names
|
||||
atom_window = "Drawing 1: Atom"
|
||||
rook_window = "Drawing 2: Rook"
|
||||
|
||||
# Create black empty images
|
||||
size = W, W, 3
|
||||
atom_image = np.zeros(size, dtype=np.uint8)
|
||||
rook_image = np.zeros(size, dtype=np.uint8)
|
||||
## [create_images]
|
||||
## [draw_atom]
|
||||
# 1. Draw a simple atom:
|
||||
# -----------------------
|
||||
|
||||
# 1.a. Creating ellipses
|
||||
my_ellipse(atom_image, 90)
|
||||
my_ellipse(atom_image, 0)
|
||||
my_ellipse(atom_image, 45)
|
||||
my_ellipse(atom_image, -45)
|
||||
|
||||
# 1.b. Creating circles
|
||||
my_filled_circle(atom_image, (W // 2, W // 2))
|
||||
## [draw_atom]
|
||||
## [draw_rook]
|
||||
|
||||
# 2. Draw a rook
|
||||
# ------------------
|
||||
# 2.a. Create a convex polygon
|
||||
my_polygon(rook_image)
|
||||
## [rectangle]
|
||||
# 2.b. Creating rectangles
|
||||
cv.rectangle(rook_image,
|
||||
(0, 7 * W // 8),
|
||||
(W, W),
|
||||
(0, 255, 255),
|
||||
-1,
|
||||
8)
|
||||
## [rectangle]
|
||||
|
||||
# 2.c. Create a few lines
|
||||
my_line(rook_image, (0, 15 * W // 16), (W, 15 * W // 16))
|
||||
my_line(rook_image, (W // 4, 7 * W // 8), (W // 4, W))
|
||||
my_line(rook_image, (W // 2, 7 * W // 8), (W // 2, W))
|
||||
my_line(rook_image, (3 * W // 4, 7 * W // 8), (3 * W // 4, W))
|
||||
## [draw_rook]
|
||||
cv.imshow(atom_window, atom_image)
|
||||
cv.moveWindow(atom_window, 0, 200)
|
||||
cv.imshow(rook_window, rook_image)
|
||||
cv.moveWindow(rook_window, W, 200)
|
||||
|
||||
cv.waitKey(0)
|
||||
cv.destroyAllWindows()
|
||||
@@ -0,0 +1,38 @@
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
|
||||
input_image = np.array((
|
||||
[0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 255, 255, 255, 0, 0, 0, 255],
|
||||
[0, 255, 255, 255, 0, 0, 0, 0],
|
||||
[0, 255, 255, 255, 0, 255, 0, 0],
|
||||
[0, 0, 255, 0, 0, 0, 0, 0],
|
||||
[0, 0, 255, 0, 0, 255, 255, 0],
|
||||
[0,255, 0, 255, 0, 0, 255, 0],
|
||||
[0, 255, 255, 255, 0, 0, 0, 0]), dtype="uint8")
|
||||
|
||||
kernel = np.array((
|
||||
[0, 1, 0],
|
||||
[1, -1, 1],
|
||||
[0, 1, 0]), dtype="int")
|
||||
|
||||
output_image = cv.morphologyEx(input_image, cv.MORPH_HITMISS, kernel)
|
||||
|
||||
rate = 50
|
||||
kernel = (kernel + 1) * 127
|
||||
kernel = np.uint8(kernel)
|
||||
|
||||
kernel = cv.resize(kernel, None, fx = rate, fy = rate, interpolation = cv.INTER_NEAREST)
|
||||
cv.imshow("kernel", kernel)
|
||||
cv.moveWindow("kernel", 0, 0)
|
||||
|
||||
input_image = cv.resize(input_image, None, fx = rate, fy = rate, interpolation = cv.INTER_NEAREST)
|
||||
cv.imshow("Original", input_image)
|
||||
cv.moveWindow("Original", 0, 200)
|
||||
|
||||
output_image = cv.resize(output_image, None , fx = rate, fy = rate, interpolation = cv.INTER_NEAREST)
|
||||
cv.imshow("Hit or Miss", output_image)
|
||||
cv.moveWindow("Hit or Miss", 500, 200)
|
||||
|
||||
cv.waitKey(0)
|
||||
cv.destroyAllWindows()
|
||||
@@ -0,0 +1,51 @@
|
||||
import sys
|
||||
import cv2 as cv
|
||||
|
||||
|
||||
def main(argv):
|
||||
print("""
|
||||
Zoom In-Out demo
|
||||
------------------
|
||||
* [i] -> Zoom [i]n
|
||||
* [o] -> Zoom [o]ut
|
||||
* [ESC] -> Close program
|
||||
""")
|
||||
## [load]
|
||||
filename = argv[0] if len(argv) > 0 else 'chicky_512.png'
|
||||
|
||||
# Load the image
|
||||
src = cv.imread(cv.samples.findFile(filename))
|
||||
|
||||
# Check if image is loaded fine
|
||||
if src is None:
|
||||
print ('Error opening image!')
|
||||
print ('Usage: pyramids.py [image_name -- default ../data/chicky_512.png] \n')
|
||||
return -1
|
||||
## [load]
|
||||
## [loop]
|
||||
while 1:
|
||||
rows, cols, _channels = map(int, src.shape)
|
||||
## [show_image]
|
||||
cv.imshow('Pyramids Demo', src)
|
||||
## [show_image]
|
||||
k = cv.waitKey(0)
|
||||
|
||||
if k == 27:
|
||||
break
|
||||
## [pyrup]
|
||||
elif chr(k) == 'i':
|
||||
src = cv.pyrUp(src, dstsize=(2 * cols, 2 * rows))
|
||||
print ('** Zoom In: Image x 2')
|
||||
## [pyrup]
|
||||
## [pyrdown]
|
||||
elif chr(k) == 'o':
|
||||
src = cv.pyrDown(src, dstsize=(cols // 2, rows // 2))
|
||||
print ('** Zoom Out: Image / 2')
|
||||
## [pyrdown]
|
||||
## [loop]
|
||||
|
||||
cv.destroyAllWindows()
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv[1:])
|
||||
@@ -0,0 +1,107 @@
|
||||
import sys
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
|
||||
# Global Variables
|
||||
|
||||
DELAY_CAPTION = 1500
|
||||
DELAY_BLUR = 100
|
||||
MAX_KERNEL_LENGTH = 31
|
||||
|
||||
src = None
|
||||
dst = None
|
||||
window_name = 'Smoothing Demo'
|
||||
|
||||
|
||||
def main(argv):
|
||||
cv.namedWindow(window_name, cv.WINDOW_AUTOSIZE)
|
||||
|
||||
# Load the source image
|
||||
imageName = argv[0] if len(argv) > 0 else 'lena.jpg'
|
||||
|
||||
global src
|
||||
src = cv.imread(cv.samples.findFile(imageName))
|
||||
if src is None:
|
||||
print ('Error opening image')
|
||||
print ('Usage: smoothing.py [image_name -- default ../data/lena.jpg] \n')
|
||||
return -1
|
||||
|
||||
if display_caption('Original Image') != 0:
|
||||
return 0
|
||||
|
||||
global dst
|
||||
dst = np.copy(src)
|
||||
if display_dst(DELAY_CAPTION) != 0:
|
||||
return 0
|
||||
|
||||
# Applying Homogeneous blur
|
||||
if display_caption('Homogeneous Blur') != 0:
|
||||
return 0
|
||||
|
||||
## [blur]
|
||||
for i in range(1, MAX_KERNEL_LENGTH, 2):
|
||||
dst = cv.blur(src, (i, i))
|
||||
if display_dst(DELAY_BLUR) != 0:
|
||||
return 0
|
||||
## [blur]
|
||||
|
||||
# Applying Gaussian blur
|
||||
if display_caption('Gaussian Blur') != 0:
|
||||
return 0
|
||||
|
||||
## [gaussianblur]
|
||||
for i in range(1, MAX_KERNEL_LENGTH, 2):
|
||||
dst = cv.GaussianBlur(src, (i, i), 0)
|
||||
if display_dst(DELAY_BLUR) != 0:
|
||||
return 0
|
||||
## [gaussianblur]
|
||||
|
||||
# Applying Median blur
|
||||
if display_caption('Median Blur') != 0:
|
||||
return 0
|
||||
|
||||
## [medianblur]
|
||||
for i in range(1, MAX_KERNEL_LENGTH, 2):
|
||||
dst = cv.medianBlur(src, i)
|
||||
if display_dst(DELAY_BLUR) != 0:
|
||||
return 0
|
||||
## [medianblur]
|
||||
|
||||
# Applying Bilateral Filter
|
||||
if display_caption('Bilateral Blur') != 0:
|
||||
return 0
|
||||
|
||||
## [bilateralfilter]
|
||||
# Remember, bilateral is a bit slow, so as value go higher, it takes long time
|
||||
for i in range(1, MAX_KERNEL_LENGTH, 2):
|
||||
dst = cv.bilateralFilter(src, i, i * 2, i / 2)
|
||||
if display_dst(DELAY_BLUR) != 0:
|
||||
return 0
|
||||
## [bilateralfilter]
|
||||
|
||||
# Done
|
||||
display_caption('Done!')
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def display_caption(caption):
|
||||
global dst
|
||||
dst = np.zeros(src.shape, src.dtype)
|
||||
rows, cols, _ch = src.shape
|
||||
cv.putText(dst, caption,
|
||||
(int(cols / 4), int(rows / 2)),
|
||||
cv.FONT_HERSHEY_COMPLEX, 1, (255, 255, 255))
|
||||
|
||||
return display_dst(DELAY_CAPTION)
|
||||
|
||||
|
||||
def display_dst(delay):
|
||||
cv.imshow(window_name, dst)
|
||||
c = cv.waitKey(delay)
|
||||
if c >= 0 : return -1
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv[1:])
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
import argparse
|
||||
|
||||
W = 52 # window size is WxW
|
||||
C_Thr = 0.43 # threshold for coherency
|
||||
LowThr = 35 # threshold1 for orientation, it ranges from 0 to 180
|
||||
HighThr = 57 # threshold2 for orientation, it ranges from 0 to 180
|
||||
|
||||
## [calcGST]
|
||||
## [calcJ_header]
|
||||
## [calcGST_proto]
|
||||
def calcGST(inputIMG, w):
|
||||
## [calcGST_proto]
|
||||
img = inputIMG.astype(np.float32)
|
||||
|
||||
# GST components calculation (start)
|
||||
# J = (J11 J12; J12 J22) - GST
|
||||
imgDiffX = cv.Sobel(img, cv.CV_32F, 1, 0, 3)
|
||||
imgDiffY = cv.Sobel(img, cv.CV_32F, 0, 1, 3)
|
||||
imgDiffXY = cv.multiply(imgDiffX, imgDiffY)
|
||||
## [calcJ_header]
|
||||
|
||||
imgDiffXX = cv.multiply(imgDiffX, imgDiffX)
|
||||
imgDiffYY = cv.multiply(imgDiffY, imgDiffY)
|
||||
|
||||
J11 = cv.boxFilter(imgDiffXX, cv.CV_32F, (w,w))
|
||||
J22 = cv.boxFilter(imgDiffYY, cv.CV_32F, (w,w))
|
||||
J12 = cv.boxFilter(imgDiffXY, cv.CV_32F, (w,w))
|
||||
# GST components calculations (stop)
|
||||
|
||||
# eigenvalue calculation (start)
|
||||
# lambda1 = 0.5*(J11 + J22 + sqrt((J11-J22)^2 + 4*J12^2))
|
||||
# lambda2 = 0.5*(J11 + J22 - sqrt((J11-J22)^2 + 4*J12^2))
|
||||
tmp1 = J11 + J22
|
||||
tmp2 = J11 - J22
|
||||
tmp2 = cv.multiply(tmp2, tmp2)
|
||||
tmp3 = cv.multiply(J12, J12)
|
||||
tmp4 = np.sqrt(tmp2 + 4.0 * tmp3)
|
||||
|
||||
lambda1 = 0.5*(tmp1 + tmp4) # biggest eigenvalue
|
||||
lambda2 = 0.5*(tmp1 - tmp4) # smallest eigenvalue
|
||||
# eigenvalue calculation (stop)
|
||||
|
||||
# Coherency calculation (start)
|
||||
# Coherency = (lambda1 - lambda2)/(lambda1 + lambda2)) - measure of anisotropism
|
||||
# Coherency is anisotropy degree (consistency of local orientation)
|
||||
imgCoherencyOut = cv.divide(lambda1 - lambda2, lambda1 + lambda2)
|
||||
# Coherency calculation (stop)
|
||||
|
||||
# orientation angle calculation (start)
|
||||
# tan(2*Alpha) = 2*J12/(J22 - J11)
|
||||
# Alpha = 0.5 atan2(2*J12/(J22 - J11))
|
||||
imgOrientationOut = cv.phase(J22 - J11, 2.0 * J12, angleInDegrees = True)
|
||||
imgOrientationOut = 0.5 * imgOrientationOut
|
||||
# orientation angle calculation (stop)
|
||||
|
||||
return imgCoherencyOut, imgOrientationOut
|
||||
## [calcGST]
|
||||
|
||||
parser = argparse.ArgumentParser(description='Code for Anisotropic image segmentation tutorial.')
|
||||
parser.add_argument('-i', '--input', help='Path to input image.', required=True)
|
||||
args = parser.parse_args()
|
||||
|
||||
imgIn = cv.imread(args.input, cv.IMREAD_GRAYSCALE)
|
||||
if imgIn is None:
|
||||
print('Could not open or find the image: {}'.format(args.input))
|
||||
exit(0)
|
||||
|
||||
## [main_extra]
|
||||
## [main]
|
||||
imgCoherency, imgOrientation = calcGST(imgIn, W)
|
||||
|
||||
## [thresholding]
|
||||
_, imgCoherencyBin = cv.threshold(imgCoherency, C_Thr, 255, cv.THRESH_BINARY)
|
||||
_, imgOrientationBin = cv.threshold(imgOrientation, LowThr, HighThr, cv.THRESH_BINARY)
|
||||
## [thresholding]
|
||||
|
||||
## [combining]
|
||||
imgBin = cv.bitwise_and(imgCoherencyBin, imgOrientationBin)
|
||||
## [combining]
|
||||
## [main]
|
||||
|
||||
imgCoherency = cv.normalize(imgCoherency, None, alpha=0, beta=1, norm_type=cv.NORM_MINMAX, dtype=cv.CV_32F)
|
||||
imgOrientation = cv.normalize(imgOrientation, None, alpha=0, beta=1, norm_type=cv.NORM_MINMAX, dtype=cv.CV_32F)
|
||||
|
||||
cv.imshow('result.jpg', np.uint8(0.5*(imgIn + imgBin)))
|
||||
cv.imshow('Coherency.jpg', imgCoherency)
|
||||
cv.imshow('Orientation.jpg', imgOrientation)
|
||||
cv.waitKey(0)
|
||||
## [main_extra]
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
from __future__ import print_function
|
||||
from builtins import input
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
import argparse
|
||||
|
||||
# Read image given by user
|
||||
## [basic-linear-transform-load]
|
||||
parser = argparse.ArgumentParser(description='Code for Changing the contrast and brightness of an image! tutorial.')
|
||||
parser.add_argument('--input', help='Path to input image.', default='lena.jpg')
|
||||
args = parser.parse_args()
|
||||
|
||||
image = cv.imread(cv.samples.findFile(args.input))
|
||||
if image is None:
|
||||
print('Could not open or find the image: ', args.input)
|
||||
exit(0)
|
||||
## [basic-linear-transform-load]
|
||||
|
||||
## [basic-linear-transform-output]
|
||||
new_image = np.zeros(image.shape, image.dtype)
|
||||
## [basic-linear-transform-output]
|
||||
|
||||
## [basic-linear-transform-parameters]
|
||||
alpha = 1.0 # Simple contrast control
|
||||
beta = 0 # Simple brightness control
|
||||
|
||||
# Initialize values
|
||||
print(' Basic Linear Transforms ')
|
||||
print('-------------------------')
|
||||
try:
|
||||
alpha = float(input('* Enter the alpha value [1.0-3.0]: '))
|
||||
beta = int(input('* Enter the beta value [0-100]: '))
|
||||
except ValueError:
|
||||
print('Error, not a number')
|
||||
## [basic-linear-transform-parameters]
|
||||
|
||||
# Do the operation new_image(i,j) = alpha*image(i,j) + beta
|
||||
# Instead of these 'for' loops we could have used simply:
|
||||
# new_image = cv.convertScaleAbs(image, alpha=alpha, beta=beta)
|
||||
# but we wanted to show you how to access the pixels :)
|
||||
## [basic-linear-transform-operation]
|
||||
for y in range(image.shape[0]):
|
||||
for x in range(image.shape[1]):
|
||||
for c in range(image.shape[2]):
|
||||
new_image[y,x,c] = np.clip(alpha*image[y,x,c] + beta, 0, 255)
|
||||
## [basic-linear-transform-operation]
|
||||
|
||||
## [basic-linear-transform-display]
|
||||
# Show stuff
|
||||
cv.imshow('Original Image', image)
|
||||
cv.imshow('New Image', new_image)
|
||||
|
||||
# Wait until user press some key
|
||||
cv.waitKey()
|
||||
## [basic-linear-transform-display]
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
from __future__ import print_function
|
||||
from __future__ import division
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
import argparse
|
||||
|
||||
alpha = 1.0
|
||||
alpha_max = 500
|
||||
beta = 0
|
||||
beta_max = 200
|
||||
gamma = 1.0
|
||||
gamma_max = 200
|
||||
|
||||
def basicLinearTransform():
|
||||
res = cv.convertScaleAbs(img_original, alpha=alpha, beta=beta)
|
||||
img_corrected = cv.hconcat([img_original, res])
|
||||
cv.imshow("Brightness and contrast adjustments", img_corrected)
|
||||
|
||||
def gammaCorrection():
|
||||
## [changing-contrast-brightness-gamma-correction]
|
||||
lookUpTable = np.empty((1,256), np.uint8)
|
||||
for i in range(256):
|
||||
lookUpTable[0,i] = np.clip(pow(i / 255.0, gamma) * 255.0, 0, 255)
|
||||
|
||||
res = cv.LUT(img_original, lookUpTable)
|
||||
## [changing-contrast-brightness-gamma-correction]
|
||||
|
||||
img_gamma_corrected = cv.hconcat([img_original, res])
|
||||
cv.imshow("Gamma correction", img_gamma_corrected)
|
||||
|
||||
def on_linear_transform_alpha_trackbar(val):
|
||||
global alpha
|
||||
alpha = val / 100
|
||||
basicLinearTransform()
|
||||
|
||||
def on_linear_transform_beta_trackbar(val):
|
||||
global beta
|
||||
beta = val - 100
|
||||
basicLinearTransform()
|
||||
|
||||
def on_gamma_correction_trackbar(val):
|
||||
global gamma
|
||||
gamma = val / 100
|
||||
gammaCorrection()
|
||||
|
||||
parser = argparse.ArgumentParser(description='Code for Changing the contrast and brightness of an image! tutorial.')
|
||||
parser.add_argument('--input', help='Path to input image.', default='lena.jpg')
|
||||
args = parser.parse_args()
|
||||
|
||||
img_original = cv.imread(cv.samples.findFile(args.input))
|
||||
if img_original is None:
|
||||
print('Could not open or find the image: ', args.input)
|
||||
exit(0)
|
||||
|
||||
img_corrected = np.empty((img_original.shape[0], img_original.shape[1]*2, img_original.shape[2]), img_original.dtype)
|
||||
img_gamma_corrected = np.empty((img_original.shape[0], img_original.shape[1]*2, img_original.shape[2]), img_original.dtype)
|
||||
|
||||
img_corrected = cv.hconcat([img_original, img_original])
|
||||
img_gamma_corrected = cv.hconcat([img_original, img_original])
|
||||
|
||||
cv.namedWindow('Brightness and contrast adjustments')
|
||||
cv.namedWindow('Gamma correction')
|
||||
|
||||
alpha_init = int(alpha *100)
|
||||
cv.createTrackbar('Alpha gain (contrast)', 'Brightness and contrast adjustments', alpha_init, alpha_max, on_linear_transform_alpha_trackbar)
|
||||
beta_init = beta + 100
|
||||
cv.createTrackbar('Beta bias (brightness)', 'Brightness and contrast adjustments', beta_init, beta_max, on_linear_transform_beta_trackbar)
|
||||
gamma_init = int(gamma * 100)
|
||||
cv.createTrackbar('Gamma correction', 'Gamma correction', gamma_init, gamma_max, on_gamma_correction_trackbar)
|
||||
|
||||
on_linear_transform_alpha_trackbar(alpha_init)
|
||||
on_gamma_correction_trackbar(gamma_init)
|
||||
|
||||
cv.waitKey()
|
||||
@@ -0,0 +1,80 @@
|
||||
from __future__ import print_function
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
import argparse
|
||||
|
||||
src = None
|
||||
erosion_size = 0
|
||||
max_elem = 3
|
||||
max_kernel_size = 21
|
||||
title_trackbar_element_shape = 'Element:\n 0: Rect \n 1: Cross \n 2: Ellipse \n 3: Diamond'
|
||||
title_trackbar_kernel_size = 'Kernel size:\n 2n +1'
|
||||
title_erosion_window = 'Erosion Demo'
|
||||
title_dilation_window = 'Dilation Demo'
|
||||
|
||||
|
||||
## [main]
|
||||
def main(image):
|
||||
global src
|
||||
src = cv.imread(cv.samples.findFile(image))
|
||||
if src is None:
|
||||
print('Could not open or find the image: ', image)
|
||||
exit(0)
|
||||
|
||||
cv.namedWindow(title_erosion_window)
|
||||
cv.createTrackbar(title_trackbar_element_shape, title_erosion_window, 0, max_elem, erosion)
|
||||
cv.createTrackbar(title_trackbar_kernel_size, title_erosion_window, 0, max_kernel_size, erosion)
|
||||
|
||||
cv.namedWindow(title_dilation_window)
|
||||
cv.createTrackbar(title_trackbar_element_shape, title_dilation_window, 0, max_elem, dilatation)
|
||||
cv.createTrackbar(title_trackbar_kernel_size, title_dilation_window, 0, max_kernel_size, dilatation)
|
||||
|
||||
erosion(0)
|
||||
dilatation(0)
|
||||
cv.waitKey()
|
||||
## [main]
|
||||
|
||||
# optional mapping of values with morphological shapes
|
||||
def morph_shape(val):
|
||||
if val == 0:
|
||||
return cv.MORPH_RECT
|
||||
elif val == 1:
|
||||
return cv.MORPH_CROSS
|
||||
elif val == 2:
|
||||
return cv.MORPH_ELLIPSE
|
||||
elif val == 3:
|
||||
return cv.MORPH_DIAMOND
|
||||
|
||||
|
||||
## [erosion]
|
||||
def erosion(val):
|
||||
erosion_size = cv.getTrackbarPos(title_trackbar_kernel_size, title_erosion_window)
|
||||
erosion_shape = morph_shape(cv.getTrackbarPos(title_trackbar_element_shape, title_erosion_window))
|
||||
|
||||
## [kernel]
|
||||
element = cv.getStructuringElement(erosion_shape, (2 * erosion_size + 1, 2 * erosion_size + 1),
|
||||
(erosion_size, erosion_size))
|
||||
## [kernel]
|
||||
erosion_dst = cv.erode(src, element)
|
||||
cv.imshow(title_erosion_window, erosion_dst)
|
||||
## [erosion]
|
||||
|
||||
|
||||
## [dilation]
|
||||
def dilatation(val):
|
||||
dilatation_size = cv.getTrackbarPos(title_trackbar_kernel_size, title_dilation_window)
|
||||
dilation_shape = morph_shape(cv.getTrackbarPos(title_trackbar_element_shape, title_dilation_window))
|
||||
|
||||
element = cv.getStructuringElement(dilation_shape, (2 * dilatation_size + 1, 2 * dilatation_size + 1),
|
||||
(dilatation_size, dilatation_size))
|
||||
dilatation_dst = cv.dilate(src, element)
|
||||
cv.imshow(title_dilation_window, dilatation_dst)
|
||||
## [dilation]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description='Code for Eroding and Dilating tutorial.')
|
||||
parser.add_argument('--input', help='Path to input image.', default='LinuxLogo.jpg')
|
||||
args = parser.parse_args()
|
||||
|
||||
main(args.input)
|
||||
@@ -0,0 +1,22 @@
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
|
||||
img = cv.imread(cv.samples.findFile('sudoku.png'))
|
||||
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
|
||||
edges = cv.Canny(gray,50,150,apertureSize = 3)
|
||||
|
||||
lines = cv.HoughLines(edges,1,np.pi/180,200)
|
||||
for line in lines:
|
||||
rho,theta = line[0]
|
||||
a = np.cos(theta)
|
||||
b = np.sin(theta)
|
||||
x0 = a*rho
|
||||
y0 = b*rho
|
||||
x1 = int(x0 + 1000*(-b))
|
||||
y1 = int(y0 + 1000*(a))
|
||||
x2 = int(x0 - 1000*(-b))
|
||||
y2 = int(y0 - 1000*(a))
|
||||
|
||||
cv.line(img,(x1,y1),(x2,y2),(0,0,255),2)
|
||||
|
||||
cv.imwrite('houghlines3.jpg',img)
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
|
||||
img = cv.imread(cv.samples.findFile('sudoku.png'))
|
||||
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
|
||||
edges = cv.Canny(gray,50,150,apertureSize = 3)
|
||||
lines = cv.HoughLinesP(edges,1,np.pi/180,100,minLineLength=100,maxLineGap=10)
|
||||
for line in lines:
|
||||
x1,y1,x2,y2 = line[0]
|
||||
cv.line(img,(x1,y1),(x2,y2),(0,255,0),2)
|
||||
|
||||
cv.imwrite('houghlines5.jpg',img)
|
||||
@@ -0,0 +1,97 @@
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
import cv2 as cv
|
||||
|
||||
## [global_variables]
|
||||
use_mask = False
|
||||
img = None
|
||||
templ = None
|
||||
mask = None
|
||||
image_window = "Source Image"
|
||||
result_window = "Result window"
|
||||
|
||||
match_method = 0
|
||||
max_Trackbar = 5
|
||||
## [global_variables]
|
||||
|
||||
def main(argv):
|
||||
|
||||
if (len(sys.argv) < 3):
|
||||
print('Not enough parameters')
|
||||
print('Usage:\nmatch_template_demo.py <image_name> <template_name> [<mask_name>]')
|
||||
return -1
|
||||
|
||||
## [load_image]
|
||||
global img
|
||||
global templ
|
||||
img = cv.imread(sys.argv[1], cv.IMREAD_COLOR)
|
||||
templ = cv.imread(sys.argv[2], cv.IMREAD_COLOR)
|
||||
|
||||
if (len(sys.argv) > 3):
|
||||
global use_mask
|
||||
use_mask = True
|
||||
global mask
|
||||
mask = cv.imread( sys.argv[3], cv.IMREAD_COLOR )
|
||||
|
||||
if ((img is None) or (templ is None) or (use_mask and (mask is None))):
|
||||
print('Can\'t read one of the images')
|
||||
return -1
|
||||
## [load_image]
|
||||
|
||||
## [create_windows]
|
||||
cv.namedWindow( image_window, cv.WINDOW_AUTOSIZE )
|
||||
cv.namedWindow( result_window, cv.WINDOW_AUTOSIZE )
|
||||
## [create_windows]
|
||||
|
||||
## [create_trackbar]
|
||||
trackbar_label = 'Method: \n 0: SQDIFF \n 1: SQDIFF NORMED \n 2: TM CCORR \n 3: TM CCORR NORMED \n 4: TM COEFF \n 5: TM COEFF NORMED'
|
||||
cv.createTrackbar( trackbar_label, image_window, match_method, max_Trackbar, MatchingMethod )
|
||||
## [create_trackbar]
|
||||
|
||||
MatchingMethod(match_method)
|
||||
|
||||
## [wait_key]
|
||||
cv.waitKey(0)
|
||||
return 0
|
||||
## [wait_key]
|
||||
|
||||
def MatchingMethod(param):
|
||||
|
||||
global match_method
|
||||
match_method = param
|
||||
|
||||
## [copy_source]
|
||||
img_display = img.copy()
|
||||
## [copy_source]
|
||||
## [match_template]
|
||||
method_accepts_mask = (cv.TM_SQDIFF == match_method or match_method == cv.TM_CCORR_NORMED)
|
||||
if (use_mask and method_accepts_mask):
|
||||
result = cv.matchTemplate(img, templ, match_method, None, mask)
|
||||
else:
|
||||
result = cv.matchTemplate(img, templ, match_method)
|
||||
## [match_template]
|
||||
|
||||
## [normalize]
|
||||
cv.normalize( result, result, 0, 1, cv.NORM_MINMAX, -1 )
|
||||
## [normalize]
|
||||
## [best_match]
|
||||
_minVal, _maxVal, minLoc, maxLoc = cv.minMaxLoc(result, None)
|
||||
## [best_match]
|
||||
|
||||
## [match_loc]
|
||||
if (match_method == cv.TM_SQDIFF or match_method == cv.TM_SQDIFF_NORMED):
|
||||
matchLoc = minLoc
|
||||
else:
|
||||
matchLoc = maxLoc
|
||||
## [match_loc]
|
||||
|
||||
## [imshow]
|
||||
cv.rectangle(img_display, matchLoc, (matchLoc[0] + templ.shape[1], matchLoc[1] + templ.shape[0]), (0,0,0), 2, 8, 0 )
|
||||
cv.rectangle(result, matchLoc, (matchLoc[0] + templ.shape[1], matchLoc[1] + templ.shape[0]), (0,0,0), 2, 8, 0 )
|
||||
cv.imshow(image_window, img_display)
|
||||
cv.imshow(result_window, result)
|
||||
## [imshow]
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv[1:])
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user