Module ReMake.Raspberry_Pi.dataHandler
Expand source code
from turtle import color
import cv2
import numpy as np
import json
from datetime import datetime
import yaml
class imageproc:
"""This class works with the images taken by the camera and tries to find the laser position in them using computer vision.
"""
def __init__(self, img=None):
"""An instance of the imageproc class.
Args:
img (nparray, optional): demo image with the laser to construct the object around. Defaults to None.
"""
self.img = img
self.mask = None
self.color=color
self.hue_min = 240
self.hue_max = 265
self.sat_min = 100
self.sat_max = 255
self.val_min = 150
self.val_max = 256
self.channels = {
'hue': None,
'saturation': None,
'value': None
}
#self.crop = (0.2777, 0.07, 0.2343, 0.2734)
self.crop = (.07, 0.07, 0.147, 0.1)
def undist(self, path) -> None:
"""Undistort the current depth image using the distortion matrix coeficients and crop the image to the size of interest.
Args:
path (str): location of the distortion matrix coeficients
"""
#LOAD DISTORTION COEFICIENTS
cv_file = cv2.FileStorage(path, cv2.FILE_STORAGE_READ)
mtx = cv_file.getNode("K").mat()
dist = cv_file.getNode("D").mat()
cv_file.release()
#PERFORM THE UNDISTORTION
h, w = self.img.shape[:2]
newcameramtx, roi=cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h))
dst = cv2.undistort(self.img, mtx, dist, None, newcameramtx)
#CROP THE FINAL IMAGE TO SIZE
x,y,w,h = roi
#ex, eh, ew, ey = self.crop
#up down left right crop in procentages of the initial height and width
ey, eh, ex, ew = self.crop
bh, bw = self.img.shape[:2]
ey, eh, ex, ew = int(ey*bh), int(eh*bh), int(ex*bw), int(ew*bw)
dst = dst[y+ey:y+h-eh, x+ex:x+w-ew]
self.img = dst
def undistC(self, path) -> None:
"""Undistort the current color image using the distortion matrix coeficients and crop the image to the size of interest.
Args:
path (str): location of the distortion matrix coeficients
"""
#LOAD DISTORTION COEFICIENTS
cv_file = cv2.FileStorage(path, cv2.FILE_STORAGE_READ)
mtx = cv_file.getNode("K").mat()
dist = cv_file.getNode("D").mat()
cv_file.release()
#PERFORM THE UNDISTORTION
h, w = self.color.shape[:2]
newcameramtx, roi=cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h))
dst = cv2.undistort(self.color, mtx, dist, None, newcameramtx)
#CROP THE FINAL IMAGE TO SIZE
x,y,w,h = roi
#ex, eh, ew, ey = self.crop
#up down left right crop in procentages of the initial height and width
ey, eh, ex, ew = self.crop
bh, bw = self.color.shape[:2]
ey, eh, ex, ew = int(ey*bh), int(eh*bh), int(ex*bw), int(ew*bw)
dst = dst[y+ey:y+h-eh, x+ex:x+w-ew]
self.color = dst
def changePerspective(self) -> None:
"""Fix the perspective of the camera.
NOT YET IMPLEMENTED! DO NOT USE!
"""
#I have no idea how to do it
#To be made
pass
def localMaxToImg(self, mask, dh):
"""Tries to determine the laser position in the picture using a primitive algorithm and the intensity of the color.
Args:
mask (nparray): mask with the laser area
dh (int): maximum color intensity difference from average
Returns:
nparray: laser position encoded in a boolean array
"""
im = cv2.bitwise_and(self.img, self.img, mask=mask)
im = cv2.cvtColor(im, cv2.COLOR_BGR2HLS)
sum = im.sum(axis=(0,1))
nr = np.count_nonzero(im, axis=(0,1))
avg = sum/nr
test = np.zeros(im.shape)
for k, lines in enumerate(im):
mx=0
poz=0
for p, pixel in enumerate(lines):
if pixel[1] > mx and abs(avg[0]-pixel[0]) <= dh:
mx = pixel[1]
poz = p
test[k][poz]=255
return test
def localMax(self, mask, dh):
"""Tries to determine the laser position in the picture using a primitive algorithm and the intensity of the color.
Args:
mask (nparray): mask with the laser area
dh (int): maximum color intensity difference from average
Returns:
list: laser possition encoded in a list of indexes
"""
points =[]
im = cv2.bitwise_and(self.img, self.img, mask=mask)
im = cv2.cvtColor(im, cv2.COLOR_BGR2HLS)
sum = im.sum(axis=(0,1))
nr = np.count_nonzero(im, axis=(0,1))
avg = sum/nr
for k, lines in enumerate(im):
mx=0
poz=-1
for p, pixel in enumerate(lines):
if pixel[1] > mx and abs(avg[0]-pixel[0]) <= dh:
mx = pixel[1]
poz = p
col = list(self.color[k, poz])
points.append([poz] + col)
return points
def localMaxDIVIDEIMPERA(self, mask):
"""Tries to determine the laser position in the picture using a gready algorithm based on Divide et Impera.
Args:
mask (nparray): mask with the laser area
Returns:
list: laser possition encoded in a list of indexes
"""
im = cv2.bitwise_and(self.img, self.img, mask=mask)
im = cv2.cvtColor(im, cv2.COLOR_BGR2HLS)
cv2.imshow('GG', im)
sum = im.sum(axis=(0,1))
nr = np.count_nonzero(im, axis=(0,1))
avg = sum/nr
print(avg)
test = np.zeros(im.shape)
for k, lines in enumerate(im):
l = np.copy(lines)
order = np.arange(l.shape[0]).reshape(-1,1)
l = np.hstack((l,order))
#l= 610 *3
#h1 s1 v1
#h2 s2 v2
#etc
l = l[np.argsort(l[:, 1])] #sort the l by the V component
n=l.shape[0]
h=avg[0]
p=0
u=n-1
while p<=u:
m = int((p+u)/2)
if l[m][0]<= h:
p=m+1
else:
u=m-1
if u>=0:
st = u
else:
st = 0
p=0
u=n-1
while p<=u:
m = int((p+u)/2)
if l[m][0] >= h:
u=m-1
else:
p=m+1
if p<n:
dr = p
else:
dr = 0
if abs(h - l[st][0]) < abs(h - l[dr][0]):
f=st
else:
f=dr
test[k][l[n-1][3]]=255
#l.flatten().tofile(f, sep='||')
#f.write('-----------------------\n')
return test
def localMaxQUICK(self, mask):
"""Tries to determine the laser position in the picture using an algorithm based on QuickSort.
Args:
mask (nparray): mask with the laser area
Returns:
list: laser possition encoded in a list of indexes
"""
points =[]
im = cv2.bitwise_and(self.img, self.img, mask=mask)
imhls = cv2.cvtColor(im, cv2.COLOR_BGR2HLS)
test = np.zeros(im.shape)
for k, lines in enumerate(imhls):
if np.sum(mask[k]) > 0:
l = np.copy(lines)
order = np.arange(l.shape[0]).reshape(-1,1)
l = np.hstack((l,order))
#l= 610 *3
#h1 s1 v1
#h2 s2 v2
#etc
l = l[np.argsort(l[:, 1])] #sort the l by the V component
n=l.shape[0]
poz = l[-1][3]
col = list(self.color[k, poz])
else:
poz=-1
col=[0,0,0]
#print('Linia {} nu contine puncte'.format(k))
points.append([poz] + col)
return points
def combineFilter(self, dilate = 2):
"""Combine multiple filters(masks) into a single one to eliminate errors.
Args:
dilate (int, optional): magnitude of dilatation used. Defaults to 2.
Returns:
nparray: the combined filter(mask)
"""
m1 = self.colorFilter()
m2 = self.hsvFilter()
m1 = cv2.GaussianBlur(m1,(5,5),0)
m2 = cv2.GaussianBlur(m2,(5,5),0)
m1 = self.dilate(m1,dilate)
m2 = self.dilate(m2,dilate)
mask = cv2.bitwise_and(m1, m2)
mask = cv2.GaussianBlur(mask,(5,5),0)
mask = cv2.threshold(mask, 20, 255, cv2.THRESH_BINARY)[1]
return mask
def dilate(self,img,size):
"""Apply the dilatation transformation to an image.
Args:
img (nparray): surce image
size (int): magnitude of dilatation
Returns:
nparray: the dilatated image
"""
dilatation_size = size
dilation_shape = cv2.MORPH_ELLIPSE
element = cv2.getStructuringElement(dilation_shape, (2 * dilatation_size + 1, 2 * dilatation_size + 1), (dilatation_size, dilatation_size))
return cv2.dilate(img, element)
def colorFilter(self, ch=0):
"""Generate a filter(mask) based on the colors in the image.
Args:
ch (int, optional): color channel used. Defaults to 0 (for red lasers).
Returns:
nparray: filter generated as a boolean array
"""
if ch == 0:
lowerb = np.array([120, 0, 0])
upperb = np.array([255, 120, 120])
elif ch == 1:
lowerb = np.array([0, 120, 0])
upperb = np.array([120, 255, 120])
elif ch == 2:
lowerb = np.array([0, 0, 120])
upperb = np.array([120, 120, 255])
lowert = 40
uppert = 255
#1200,1600
self.mask = cv2.inRange(self.img, lowerb, upperb)
temp = cv2.bitwise_and(self.img, self.img, mask=self.mask)
ch = temp[:,:,ch]
ch = cv2.threshold(ch, lowert, uppert, cv2.THRESH_BINARY)[1]
return ch
def hsvFilter(self):
"""Generate a filter(mask) based on the saturation and the HSV decomposition of the image.
Returns:
nparray: filter generated as a boolean array
"""
hsv_img = cv2.cvtColor(self.img, cv2.COLOR_BGR2HSV)
# split the video frame into color channels
h, s, v = cv2.split(hsv_img)
self.channels['hue'] = h
self.channels['saturation'] = s
self.channels['value'] = v
# Threshold ranges of HSV components; storing the results in place
self.threshold_image("hue")
self.threshold_image("saturation")
self.threshold_image("value")
# Perform an AND on HSV components to identify the laser!
mask = cv2.bitwise_and(self.channels['hue'], self.channels['value'])
mask = cv2.bitwise_and(self.channels['saturation'], mask)
return mask
def threshold_image(self, channel) -> None:
"""Apply a treshhold operation to the specific HSV channel.
Args:
channel (str): channel which the transformation should be applied
"""
if channel == "hue":
minimum = self.hue_min
maximum = self.hue_max
elif channel == "saturation":
minimum = self.sat_min
maximum = self.sat_max
elif channel == "value":
minimum = self.val_min
maximum = self.val_max
(t, tmp) = cv2.threshold(
self.channels[channel], # src
maximum, # threshold value
0, # we dont care because of the selected type
cv2.THRESH_TOZERO_INV # t type
)
(t, self.channels[channel]) = cv2.threshold(
tmp, # src
minimum, # threshold value
255, # maxvalue
cv2.THRESH_BINARY # type
)
if channel == 'hue':
self.channels['hue'] = cv2.bitwise_not(self.channels['hue'])
def getImg(self):
"""Get current depth image in the buffer.
Returns:
nparray: image
"""
return self.img
def getRes(self):
"""Get the resolution of the scan.
Returns:
list: resolution of the scan
"""
return (self.img.shape[0], self.img.shape[1])
def setImg(self, img) -> None:
"""Set a depth image to the internal buffer.
Args:
img (nparray): image to be set
"""
self.img = img
def setColor(self, img) -> None:
"""Set a color image to the internal buffer.
Args:
img (nparray): image to be set
"""
self.color = img
def getMask(self, mask):
"""Get the image with the filter applied.
Args:
mask (nparray): filter to be used
Returns:
nparray: image generated
"""
return cv2.bitwise_and(self.img, self.img, mask=mask)
class writer:
"""This class is used to arrange, sanitize and save the data generated by the scanner in a JSON file type.
"""
def __init__(self, fname) -> None:
"""A writter for the scan data.
Args:
fname (str): filename of the data to be saved
"""
self.fname = fname
self.res = (0,0)
self.points = []
self.angle = []
self.weight = 0
self.toppoints = []
self.topangle = []
def setHeader(self, res, weight=0) -> None:
"""Set the top data of the file.
Args:
res (list): resolution used to scan
weight (float, optional): weight of the object scanned. Defaults to 0.
"""
self.res = res
self.weight = weight
def addData(self, line, angle) -> None:
"""Add data to the internal buffer.
Args:
line (nparray): list of laser position with color information
angle (float): angle of the measurement
"""
self.points.append(line)
self.angle.append(angle)
def addDataTop(self, line, angle) -> None:
"""Add data for the top side to the internal buffer.
Args:
line (nparray): list of laser position with color information
angle (float): angle of the measurement
"""
self.toppoints.append(line)
self.topangle.append(angle)
def save(self) -> None:
"""Save the data into a JSON file.
"""
template = {
"date" : datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"res": self.res,
"weght": self.weight,
"samples": [],
"top" : []
}
samples = template['samples']
points_arr = np.array(self.points)
#print(points_arr)
#points_arr.reshape((nsamples, self.res[0]))
for k, line in enumerate(points_arr):
sample_template = {
"angle": self.angle[k],
"points": line.tolist()
}
samples.append(sample_template)
topsamples = template['top']
toppoints_arr = np.array(self.toppoints)
for k, line in enumerate(toppoints_arr):
sample_template = {
"angle": self.topangle[k],
"points": line.tolist()
}
topsamples.append(sample_template)
data = json.dumps(template, indent=4)
with open(self.fname, 'w') as js:
js.write(data)
Classes
class imageproc (img=None)
-
This class works with the images taken by the camera and tries to find the laser position in them using computer vision.
An instance of the imageproc class.
Args
img
:nparray
, optional- demo image with the laser to construct the object around. Defaults to None.
Expand source code
class imageproc: """This class works with the images taken by the camera and tries to find the laser position in them using computer vision. """ def __init__(self, img=None): """An instance of the imageproc class. Args: img (nparray, optional): demo image with the laser to construct the object around. Defaults to None. """ self.img = img self.mask = None self.color=color self.hue_min = 240 self.hue_max = 265 self.sat_min = 100 self.sat_max = 255 self.val_min = 150 self.val_max = 256 self.channels = { 'hue': None, 'saturation': None, 'value': None } #self.crop = (0.2777, 0.07, 0.2343, 0.2734) self.crop = (.07, 0.07, 0.147, 0.1) def undist(self, path) -> None: """Undistort the current depth image using the distortion matrix coeficients and crop the image to the size of interest. Args: path (str): location of the distortion matrix coeficients """ #LOAD DISTORTION COEFICIENTS cv_file = cv2.FileStorage(path, cv2.FILE_STORAGE_READ) mtx = cv_file.getNode("K").mat() dist = cv_file.getNode("D").mat() cv_file.release() #PERFORM THE UNDISTORTION h, w = self.img.shape[:2] newcameramtx, roi=cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h)) dst = cv2.undistort(self.img, mtx, dist, None, newcameramtx) #CROP THE FINAL IMAGE TO SIZE x,y,w,h = roi #ex, eh, ew, ey = self.crop #up down left right crop in procentages of the initial height and width ey, eh, ex, ew = self.crop bh, bw = self.img.shape[:2] ey, eh, ex, ew = int(ey*bh), int(eh*bh), int(ex*bw), int(ew*bw) dst = dst[y+ey:y+h-eh, x+ex:x+w-ew] self.img = dst def undistC(self, path) -> None: """Undistort the current color image using the distortion matrix coeficients and crop the image to the size of interest. Args: path (str): location of the distortion matrix coeficients """ #LOAD DISTORTION COEFICIENTS cv_file = cv2.FileStorage(path, cv2.FILE_STORAGE_READ) mtx = cv_file.getNode("K").mat() dist = cv_file.getNode("D").mat() cv_file.release() #PERFORM THE UNDISTORTION h, w = self.color.shape[:2] newcameramtx, roi=cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h)) dst = cv2.undistort(self.color, mtx, dist, None, newcameramtx) #CROP THE FINAL IMAGE TO SIZE x,y,w,h = roi #ex, eh, ew, ey = self.crop #up down left right crop in procentages of the initial height and width ey, eh, ex, ew = self.crop bh, bw = self.color.shape[:2] ey, eh, ex, ew = int(ey*bh), int(eh*bh), int(ex*bw), int(ew*bw) dst = dst[y+ey:y+h-eh, x+ex:x+w-ew] self.color = dst def changePerspective(self) -> None: """Fix the perspective of the camera. NOT YET IMPLEMENTED! DO NOT USE! """ #I have no idea how to do it #To be made pass def localMaxToImg(self, mask, dh): """Tries to determine the laser position in the picture using a primitive algorithm and the intensity of the color. Args: mask (nparray): mask with the laser area dh (int): maximum color intensity difference from average Returns: nparray: laser position encoded in a boolean array """ im = cv2.bitwise_and(self.img, self.img, mask=mask) im = cv2.cvtColor(im, cv2.COLOR_BGR2HLS) sum = im.sum(axis=(0,1)) nr = np.count_nonzero(im, axis=(0,1)) avg = sum/nr test = np.zeros(im.shape) for k, lines in enumerate(im): mx=0 poz=0 for p, pixel in enumerate(lines): if pixel[1] > mx and abs(avg[0]-pixel[0]) <= dh: mx = pixel[1] poz = p test[k][poz]=255 return test def localMax(self, mask, dh): """Tries to determine the laser position in the picture using a primitive algorithm and the intensity of the color. Args: mask (nparray): mask with the laser area dh (int): maximum color intensity difference from average Returns: list: laser possition encoded in a list of indexes """ points =[] im = cv2.bitwise_and(self.img, self.img, mask=mask) im = cv2.cvtColor(im, cv2.COLOR_BGR2HLS) sum = im.sum(axis=(0,1)) nr = np.count_nonzero(im, axis=(0,1)) avg = sum/nr for k, lines in enumerate(im): mx=0 poz=-1 for p, pixel in enumerate(lines): if pixel[1] > mx and abs(avg[0]-pixel[0]) <= dh: mx = pixel[1] poz = p col = list(self.color[k, poz]) points.append([poz] + col) return points def localMaxDIVIDEIMPERA(self, mask): """Tries to determine the laser position in the picture using a gready algorithm based on Divide et Impera. Args: mask (nparray): mask with the laser area Returns: list: laser possition encoded in a list of indexes """ im = cv2.bitwise_and(self.img, self.img, mask=mask) im = cv2.cvtColor(im, cv2.COLOR_BGR2HLS) cv2.imshow('GG', im) sum = im.sum(axis=(0,1)) nr = np.count_nonzero(im, axis=(0,1)) avg = sum/nr print(avg) test = np.zeros(im.shape) for k, lines in enumerate(im): l = np.copy(lines) order = np.arange(l.shape[0]).reshape(-1,1) l = np.hstack((l,order)) #l= 610 *3 #h1 s1 v1 #h2 s2 v2 #etc l = l[np.argsort(l[:, 1])] #sort the l by the V component n=l.shape[0] h=avg[0] p=0 u=n-1 while p<=u: m = int((p+u)/2) if l[m][0]<= h: p=m+1 else: u=m-1 if u>=0: st = u else: st = 0 p=0 u=n-1 while p<=u: m = int((p+u)/2) if l[m][0] >= h: u=m-1 else: p=m+1 if p<n: dr = p else: dr = 0 if abs(h - l[st][0]) < abs(h - l[dr][0]): f=st else: f=dr test[k][l[n-1][3]]=255 #l.flatten().tofile(f, sep='||') #f.write('-----------------------\n') return test def localMaxQUICK(self, mask): """Tries to determine the laser position in the picture using an algorithm based on QuickSort. Args: mask (nparray): mask with the laser area Returns: list: laser possition encoded in a list of indexes """ points =[] im = cv2.bitwise_and(self.img, self.img, mask=mask) imhls = cv2.cvtColor(im, cv2.COLOR_BGR2HLS) test = np.zeros(im.shape) for k, lines in enumerate(imhls): if np.sum(mask[k]) > 0: l = np.copy(lines) order = np.arange(l.shape[0]).reshape(-1,1) l = np.hstack((l,order)) #l= 610 *3 #h1 s1 v1 #h2 s2 v2 #etc l = l[np.argsort(l[:, 1])] #sort the l by the V component n=l.shape[0] poz = l[-1][3] col = list(self.color[k, poz]) else: poz=-1 col=[0,0,0] #print('Linia {} nu contine puncte'.format(k)) points.append([poz] + col) return points def combineFilter(self, dilate = 2): """Combine multiple filters(masks) into a single one to eliminate errors. Args: dilate (int, optional): magnitude of dilatation used. Defaults to 2. Returns: nparray: the combined filter(mask) """ m1 = self.colorFilter() m2 = self.hsvFilter() m1 = cv2.GaussianBlur(m1,(5,5),0) m2 = cv2.GaussianBlur(m2,(5,5),0) m1 = self.dilate(m1,dilate) m2 = self.dilate(m2,dilate) mask = cv2.bitwise_and(m1, m2) mask = cv2.GaussianBlur(mask,(5,5),0) mask = cv2.threshold(mask, 20, 255, cv2.THRESH_BINARY)[1] return mask def dilate(self,img,size): """Apply the dilatation transformation to an image. Args: img (nparray): surce image size (int): magnitude of dilatation Returns: nparray: the dilatated image """ dilatation_size = size dilation_shape = cv2.MORPH_ELLIPSE element = cv2.getStructuringElement(dilation_shape, (2 * dilatation_size + 1, 2 * dilatation_size + 1), (dilatation_size, dilatation_size)) return cv2.dilate(img, element) def colorFilter(self, ch=0): """Generate a filter(mask) based on the colors in the image. Args: ch (int, optional): color channel used. Defaults to 0 (for red lasers). Returns: nparray: filter generated as a boolean array """ if ch == 0: lowerb = np.array([120, 0, 0]) upperb = np.array([255, 120, 120]) elif ch == 1: lowerb = np.array([0, 120, 0]) upperb = np.array([120, 255, 120]) elif ch == 2: lowerb = np.array([0, 0, 120]) upperb = np.array([120, 120, 255]) lowert = 40 uppert = 255 #1200,1600 self.mask = cv2.inRange(self.img, lowerb, upperb) temp = cv2.bitwise_and(self.img, self.img, mask=self.mask) ch = temp[:,:,ch] ch = cv2.threshold(ch, lowert, uppert, cv2.THRESH_BINARY)[1] return ch def hsvFilter(self): """Generate a filter(mask) based on the saturation and the HSV decomposition of the image. Returns: nparray: filter generated as a boolean array """ hsv_img = cv2.cvtColor(self.img, cv2.COLOR_BGR2HSV) # split the video frame into color channels h, s, v = cv2.split(hsv_img) self.channels['hue'] = h self.channels['saturation'] = s self.channels['value'] = v # Threshold ranges of HSV components; storing the results in place self.threshold_image("hue") self.threshold_image("saturation") self.threshold_image("value") # Perform an AND on HSV components to identify the laser! mask = cv2.bitwise_and(self.channels['hue'], self.channels['value']) mask = cv2.bitwise_and(self.channels['saturation'], mask) return mask def threshold_image(self, channel) -> None: """Apply a treshhold operation to the specific HSV channel. Args: channel (str): channel which the transformation should be applied """ if channel == "hue": minimum = self.hue_min maximum = self.hue_max elif channel == "saturation": minimum = self.sat_min maximum = self.sat_max elif channel == "value": minimum = self.val_min maximum = self.val_max (t, tmp) = cv2.threshold( self.channels[channel], # src maximum, # threshold value 0, # we dont care because of the selected type cv2.THRESH_TOZERO_INV # t type ) (t, self.channels[channel]) = cv2.threshold( tmp, # src minimum, # threshold value 255, # maxvalue cv2.THRESH_BINARY # type ) if channel == 'hue': self.channels['hue'] = cv2.bitwise_not(self.channels['hue']) def getImg(self): """Get current depth image in the buffer. Returns: nparray: image """ return self.img def getRes(self): """Get the resolution of the scan. Returns: list: resolution of the scan """ return (self.img.shape[0], self.img.shape[1]) def setImg(self, img) -> None: """Set a depth image to the internal buffer. Args: img (nparray): image to be set """ self.img = img def setColor(self, img) -> None: """Set a color image to the internal buffer. Args: img (nparray): image to be set """ self.color = img def getMask(self, mask): """Get the image with the filter applied. Args: mask (nparray): filter to be used Returns: nparray: image generated """ return cv2.bitwise_and(self.img, self.img, mask=mask)
Methods
def changePerspective(self) ‑> None
-
Fix the perspective of the camera. NOT YET IMPLEMENTED! DO NOT USE!
Expand source code
def changePerspective(self) -> None: """Fix the perspective of the camera. NOT YET IMPLEMENTED! DO NOT USE! """ #I have no idea how to do it #To be made pass
def colorFilter(self, ch=0)
-
Generate a filter(mask) based on the colors in the image.
Args
ch
:int
, optional- color channel used. Defaults to 0 (for red lasers).
Returns
nparray
- filter generated as a boolean array
Expand source code
def colorFilter(self, ch=0): """Generate a filter(mask) based on the colors in the image. Args: ch (int, optional): color channel used. Defaults to 0 (for red lasers). Returns: nparray: filter generated as a boolean array """ if ch == 0: lowerb = np.array([120, 0, 0]) upperb = np.array([255, 120, 120]) elif ch == 1: lowerb = np.array([0, 120, 0]) upperb = np.array([120, 255, 120]) elif ch == 2: lowerb = np.array([0, 0, 120]) upperb = np.array([120, 120, 255]) lowert = 40 uppert = 255 #1200,1600 self.mask = cv2.inRange(self.img, lowerb, upperb) temp = cv2.bitwise_and(self.img, self.img, mask=self.mask) ch = temp[:,:,ch] ch = cv2.threshold(ch, lowert, uppert, cv2.THRESH_BINARY)[1] return ch
def combineFilter(self, dilate=2)
-
Combine multiple filters(masks) into a single one to eliminate errors.
Args
dilate
:int
, optional- magnitude of dilatation used. Defaults to 2.
Returns
nparray
- the combined filter(mask)
Expand source code
def combineFilter(self, dilate = 2): """Combine multiple filters(masks) into a single one to eliminate errors. Args: dilate (int, optional): magnitude of dilatation used. Defaults to 2. Returns: nparray: the combined filter(mask) """ m1 = self.colorFilter() m2 = self.hsvFilter() m1 = cv2.GaussianBlur(m1,(5,5),0) m2 = cv2.GaussianBlur(m2,(5,5),0) m1 = self.dilate(m1,dilate) m2 = self.dilate(m2,dilate) mask = cv2.bitwise_and(m1, m2) mask = cv2.GaussianBlur(mask,(5,5),0) mask = cv2.threshold(mask, 20, 255, cv2.THRESH_BINARY)[1] return mask
def dilate(self, img, size)
-
Apply the dilatation transformation to an image.
Args
img
:nparray
- surce image
size
:int
- magnitude of dilatation
Returns
nparray
- the dilatated image
Expand source code
def dilate(self,img,size): """Apply the dilatation transformation to an image. Args: img (nparray): surce image size (int): magnitude of dilatation Returns: nparray: the dilatated image """ dilatation_size = size dilation_shape = cv2.MORPH_ELLIPSE element = cv2.getStructuringElement(dilation_shape, (2 * dilatation_size + 1, 2 * dilatation_size + 1), (dilatation_size, dilatation_size)) return cv2.dilate(img, element)
def getImg(self)
-
Get current depth image in the buffer.
Returns
nparray
- image
Expand source code
def getImg(self): """Get current depth image in the buffer. Returns: nparray: image """ return self.img
def getMask(self, mask)
-
Get the image with the filter applied.
Args
mask
:nparray
- filter to be used
Returns
nparray
- image generated
Expand source code
def getMask(self, mask): """Get the image with the filter applied. Args: mask (nparray): filter to be used Returns: nparray: image generated """ return cv2.bitwise_and(self.img, self.img, mask=mask)
def getRes(self)
-
Get the resolution of the scan.
Returns
list
- resolution of the scan
Expand source code
def getRes(self): """Get the resolution of the scan. Returns: list: resolution of the scan """ return (self.img.shape[0], self.img.shape[1])
def hsvFilter(self)
-
Generate a filter(mask) based on the saturation and the HSV decomposition of the image.
Returns
nparray
- filter generated as a boolean array
Expand source code
def hsvFilter(self): """Generate a filter(mask) based on the saturation and the HSV decomposition of the image. Returns: nparray: filter generated as a boolean array """ hsv_img = cv2.cvtColor(self.img, cv2.COLOR_BGR2HSV) # split the video frame into color channels h, s, v = cv2.split(hsv_img) self.channels['hue'] = h self.channels['saturation'] = s self.channels['value'] = v # Threshold ranges of HSV components; storing the results in place self.threshold_image("hue") self.threshold_image("saturation") self.threshold_image("value") # Perform an AND on HSV components to identify the laser! mask = cv2.bitwise_and(self.channels['hue'], self.channels['value']) mask = cv2.bitwise_and(self.channels['saturation'], mask) return mask
def localMax(self, mask, dh)
-
Tries to determine the laser position in the picture using a primitive algorithm and the intensity of the color.
Args
mask
:nparray
- mask with the laser area
dh
:int
- maximum color intensity difference from average
Returns
list
- laser possition encoded in a list of indexes
Expand source code
def localMax(self, mask, dh): """Tries to determine the laser position in the picture using a primitive algorithm and the intensity of the color. Args: mask (nparray): mask with the laser area dh (int): maximum color intensity difference from average Returns: list: laser possition encoded in a list of indexes """ points =[] im = cv2.bitwise_and(self.img, self.img, mask=mask) im = cv2.cvtColor(im, cv2.COLOR_BGR2HLS) sum = im.sum(axis=(0,1)) nr = np.count_nonzero(im, axis=(0,1)) avg = sum/nr for k, lines in enumerate(im): mx=0 poz=-1 for p, pixel in enumerate(lines): if pixel[1] > mx and abs(avg[0]-pixel[0]) <= dh: mx = pixel[1] poz = p col = list(self.color[k, poz]) points.append([poz] + col) return points
def localMaxDIVIDEIMPERA(self, mask)
-
Tries to determine the laser position in the picture using a gready algorithm based on Divide et Impera.
Args
mask
:nparray
- mask with the laser area
Returns
list
- laser possition encoded in a list of indexes
Expand source code
def localMaxDIVIDEIMPERA(self, mask): """Tries to determine the laser position in the picture using a gready algorithm based on Divide et Impera. Args: mask (nparray): mask with the laser area Returns: list: laser possition encoded in a list of indexes """ im = cv2.bitwise_and(self.img, self.img, mask=mask) im = cv2.cvtColor(im, cv2.COLOR_BGR2HLS) cv2.imshow('GG', im) sum = im.sum(axis=(0,1)) nr = np.count_nonzero(im, axis=(0,1)) avg = sum/nr print(avg) test = np.zeros(im.shape) for k, lines in enumerate(im): l = np.copy(lines) order = np.arange(l.shape[0]).reshape(-1,1) l = np.hstack((l,order)) #l= 610 *3 #h1 s1 v1 #h2 s2 v2 #etc l = l[np.argsort(l[:, 1])] #sort the l by the V component n=l.shape[0] h=avg[0] p=0 u=n-1 while p<=u: m = int((p+u)/2) if l[m][0]<= h: p=m+1 else: u=m-1 if u>=0: st = u else: st = 0 p=0 u=n-1 while p<=u: m = int((p+u)/2) if l[m][0] >= h: u=m-1 else: p=m+1 if p<n: dr = p else: dr = 0 if abs(h - l[st][0]) < abs(h - l[dr][0]): f=st else: f=dr test[k][l[n-1][3]]=255 #l.flatten().tofile(f, sep='||') #f.write('-----------------------\n') return test
def localMaxQUICK(self, mask)
-
Tries to determine the laser position in the picture using an algorithm based on QuickSort.
Args
mask
:nparray
- mask with the laser area
Returns
list
- laser possition encoded in a list of indexes
Expand source code
def localMaxQUICK(self, mask): """Tries to determine the laser position in the picture using an algorithm based on QuickSort. Args: mask (nparray): mask with the laser area Returns: list: laser possition encoded in a list of indexes """ points =[] im = cv2.bitwise_and(self.img, self.img, mask=mask) imhls = cv2.cvtColor(im, cv2.COLOR_BGR2HLS) test = np.zeros(im.shape) for k, lines in enumerate(imhls): if np.sum(mask[k]) > 0: l = np.copy(lines) order = np.arange(l.shape[0]).reshape(-1,1) l = np.hstack((l,order)) #l= 610 *3 #h1 s1 v1 #h2 s2 v2 #etc l = l[np.argsort(l[:, 1])] #sort the l by the V component n=l.shape[0] poz = l[-1][3] col = list(self.color[k, poz]) else: poz=-1 col=[0,0,0] #print('Linia {} nu contine puncte'.format(k)) points.append([poz] + col) return points
def localMaxToImg(self, mask, dh)
-
Tries to determine the laser position in the picture using a primitive algorithm and the intensity of the color.
Args
mask
:nparray
- mask with the laser area
dh
:int
- maximum color intensity difference from average
Returns
nparray
- laser position encoded in a boolean array
Expand source code
def localMaxToImg(self, mask, dh): """Tries to determine the laser position in the picture using a primitive algorithm and the intensity of the color. Args: mask (nparray): mask with the laser area dh (int): maximum color intensity difference from average Returns: nparray: laser position encoded in a boolean array """ im = cv2.bitwise_and(self.img, self.img, mask=mask) im = cv2.cvtColor(im, cv2.COLOR_BGR2HLS) sum = im.sum(axis=(0,1)) nr = np.count_nonzero(im, axis=(0,1)) avg = sum/nr test = np.zeros(im.shape) for k, lines in enumerate(im): mx=0 poz=0 for p, pixel in enumerate(lines): if pixel[1] > mx and abs(avg[0]-pixel[0]) <= dh: mx = pixel[1] poz = p test[k][poz]=255 return test
def setColor(self, img) ‑> None
-
Set a color image to the internal buffer.
Args
img
:nparray
- image to be set
Expand source code
def setColor(self, img) -> None: """Set a color image to the internal buffer. Args: img (nparray): image to be set """ self.color = img
def setImg(self, img) ‑> None
-
Set a depth image to the internal buffer.
Args
img
:nparray
- image to be set
Expand source code
def setImg(self, img) -> None: """Set a depth image to the internal buffer. Args: img (nparray): image to be set """ self.img = img
def threshold_image(self, channel) ‑> None
-
Apply a treshhold operation to the specific HSV channel.
Args
channel
:str
- channel which the transformation should be applied
Expand source code
def threshold_image(self, channel) -> None: """Apply a treshhold operation to the specific HSV channel. Args: channel (str): channel which the transformation should be applied """ if channel == "hue": minimum = self.hue_min maximum = self.hue_max elif channel == "saturation": minimum = self.sat_min maximum = self.sat_max elif channel == "value": minimum = self.val_min maximum = self.val_max (t, tmp) = cv2.threshold( self.channels[channel], # src maximum, # threshold value 0, # we dont care because of the selected type cv2.THRESH_TOZERO_INV # t type ) (t, self.channels[channel]) = cv2.threshold( tmp, # src minimum, # threshold value 255, # maxvalue cv2.THRESH_BINARY # type ) if channel == 'hue': self.channels['hue'] = cv2.bitwise_not(self.channels['hue'])
def undist(self, path) ‑> None
-
Undistort the current depth image using the distortion matrix coeficients and crop the image to the size of interest.
Args
path
:str
- location of the distortion matrix coeficients
Expand source code
def undist(self, path) -> None: """Undistort the current depth image using the distortion matrix coeficients and crop the image to the size of interest. Args: path (str): location of the distortion matrix coeficients """ #LOAD DISTORTION COEFICIENTS cv_file = cv2.FileStorage(path, cv2.FILE_STORAGE_READ) mtx = cv_file.getNode("K").mat() dist = cv_file.getNode("D").mat() cv_file.release() #PERFORM THE UNDISTORTION h, w = self.img.shape[:2] newcameramtx, roi=cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h)) dst = cv2.undistort(self.img, mtx, dist, None, newcameramtx) #CROP THE FINAL IMAGE TO SIZE x,y,w,h = roi #ex, eh, ew, ey = self.crop #up down left right crop in procentages of the initial height and width ey, eh, ex, ew = self.crop bh, bw = self.img.shape[:2] ey, eh, ex, ew = int(ey*bh), int(eh*bh), int(ex*bw), int(ew*bw) dst = dst[y+ey:y+h-eh, x+ex:x+w-ew] self.img = dst
def undistC(self, path) ‑> None
-
Undistort the current color image using the distortion matrix coeficients and crop the image to the size of interest.
Args
path
:str
- location of the distortion matrix coeficients
Expand source code
def undistC(self, path) -> None: """Undistort the current color image using the distortion matrix coeficients and crop the image to the size of interest. Args: path (str): location of the distortion matrix coeficients """ #LOAD DISTORTION COEFICIENTS cv_file = cv2.FileStorage(path, cv2.FILE_STORAGE_READ) mtx = cv_file.getNode("K").mat() dist = cv_file.getNode("D").mat() cv_file.release() #PERFORM THE UNDISTORTION h, w = self.color.shape[:2] newcameramtx, roi=cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h)) dst = cv2.undistort(self.color, mtx, dist, None, newcameramtx) #CROP THE FINAL IMAGE TO SIZE x,y,w,h = roi #ex, eh, ew, ey = self.crop #up down left right crop in procentages of the initial height and width ey, eh, ex, ew = self.crop bh, bw = self.color.shape[:2] ey, eh, ex, ew = int(ey*bh), int(eh*bh), int(ex*bw), int(ew*bw) dst = dst[y+ey:y+h-eh, x+ex:x+w-ew] self.color = dst
class writer (fname)
-
This class is used to arrange, sanitize and save the data generated by the scanner in a JSON file type.
A writter for the scan data.
Args
fname
:str
- filename of the data to be saved
Expand source code
class writer: """This class is used to arrange, sanitize and save the data generated by the scanner in a JSON file type. """ def __init__(self, fname) -> None: """A writter for the scan data. Args: fname (str): filename of the data to be saved """ self.fname = fname self.res = (0,0) self.points = [] self.angle = [] self.weight = 0 self.toppoints = [] self.topangle = [] def setHeader(self, res, weight=0) -> None: """Set the top data of the file. Args: res (list): resolution used to scan weight (float, optional): weight of the object scanned. Defaults to 0. """ self.res = res self.weight = weight def addData(self, line, angle) -> None: """Add data to the internal buffer. Args: line (nparray): list of laser position with color information angle (float): angle of the measurement """ self.points.append(line) self.angle.append(angle) def addDataTop(self, line, angle) -> None: """Add data for the top side to the internal buffer. Args: line (nparray): list of laser position with color information angle (float): angle of the measurement """ self.toppoints.append(line) self.topangle.append(angle) def save(self) -> None: """Save the data into a JSON file. """ template = { "date" : datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "res": self.res, "weght": self.weight, "samples": [], "top" : [] } samples = template['samples'] points_arr = np.array(self.points) #print(points_arr) #points_arr.reshape((nsamples, self.res[0])) for k, line in enumerate(points_arr): sample_template = { "angle": self.angle[k], "points": line.tolist() } samples.append(sample_template) topsamples = template['top'] toppoints_arr = np.array(self.toppoints) for k, line in enumerate(toppoints_arr): sample_template = { "angle": self.topangle[k], "points": line.tolist() } topsamples.append(sample_template) data = json.dumps(template, indent=4) with open(self.fname, 'w') as js: js.write(data)
Methods
def addData(self, line, angle) ‑> None
-
Add data to the internal buffer.
Args
line
:nparray
- list of laser position with color information
angle
:float
- angle of the measurement
Expand source code
def addData(self, line, angle) -> None: """Add data to the internal buffer. Args: line (nparray): list of laser position with color information angle (float): angle of the measurement """ self.points.append(line) self.angle.append(angle)
def addDataTop(self, line, angle) ‑> None
-
Add data for the top side to the internal buffer.
Args
line
:nparray
- list of laser position with color information
angle
:float
- angle of the measurement
Expand source code
def addDataTop(self, line, angle) -> None: """Add data for the top side to the internal buffer. Args: line (nparray): list of laser position with color information angle (float): angle of the measurement """ self.toppoints.append(line) self.topangle.append(angle)
def save(self) ‑> None
-
Save the data into a JSON file.
Expand source code
def save(self) -> None: """Save the data into a JSON file. """ template = { "date" : datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "res": self.res, "weght": self.weight, "samples": [], "top" : [] } samples = template['samples'] points_arr = np.array(self.points) #print(points_arr) #points_arr.reshape((nsamples, self.res[0])) for k, line in enumerate(points_arr): sample_template = { "angle": self.angle[k], "points": line.tolist() } samples.append(sample_template) topsamples = template['top'] toppoints_arr = np.array(self.toppoints) for k, line in enumerate(toppoints_arr): sample_template = { "angle": self.topangle[k], "points": line.tolist() } topsamples.append(sample_template) data = json.dumps(template, indent=4) with open(self.fname, 'w') as js: js.write(data)
def setHeader(self, res, weight=0) ‑> None
-
Set the top data of the file.
Args
res
:list
- resolution used to scan
weight
:float
, optional- weight of the object scanned. Defaults to 0.
Expand source code
def setHeader(self, res, weight=0) -> None: """Set the top data of the file. Args: res (list): resolution used to scan weight (float, optional): weight of the object scanned. Defaults to 0. """ self.res = res self.weight = weight