Algorithm for vertical curves detection, opencv+python - python

I’m trying to come up with an approach to find and mark the orange and green curves (Edges of a static and moving metal object). the goal is to measure the distance\angles between the two objects in real time.
I have already made a script that crops out the top & bottom 50 pixels and searches for the first “drastic” drop in darkness from left and right size but the result is not rubust enought for changing lighting conditions, the result is the bottom two images. The eyes can simply see the curved border all the time but my algo fails when lighting changes.
Any suggestion for a better way to find those edges?
(tried blur+canny but it fails misserably)
Thanks
My current algo
import cv2
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
import math
matplotlib.use('Agg')
capture = cv2.VideoCapture("rtsp://10.0.0.100:5555/vid0")
#capture = cv2.VideoCapture("src.ts")
scale_percent = 50
width = int(1088*scale_percent/100)
height = int(1080*scale_percent/100)
fig, ax = plt.subplots(figsize=(544/72, 540/72), dpi=72)
fig.tight_layout()
ax.set_xlim(0,width)
ax.set_ylim(-2,1)
lines = {}
lines["upper"] = ax.plot(np.arange(width), np.zeros((width,)), c='blue', lw=1, alpha=1, label='RGB')[0]
lines["lower"] = ax.plot(np.arange(width), np.zeros((width,)), c='blue', lw=1, alpha=1, label='RGB')[0]
lines["upperAvg"] = ax.plot(np.arange(width), np.zeros((width,)), c='black', lw=1, alpha=1, label='RGB')[0]
lines["upperAvgDelta"] = ax.plot(np.arange(width), np.zeros((width,)), c='red', lw=1, alpha=1, label='RGB')[0]
lines["uppermeanAvg"] = ax.plot(np.arange(width), np.zeros((width,)), c='orange', lw=1, alpha=1, label='RGB')[0]
lines["lowerAvg"] = ax.plot(np.arange(width), np.zeros((width,)), c='black', lw=1, alpha=1, label='RGB')[0]
lines["lowerAvgDelta"] = ax.plot(np.arange(width), np.zeros((width,)), c='red', lw=1, alpha=1, label='RGB')[0]
lines["lowermeanAvg"] = ax.plot(np.arange(width), np.zeros((width,)), c='orange', lw=1, alpha=1, label='RGB')[0]
def moving_average(a, n) :
ret = np.cumsum(a, dtype=float)
ret[n:] = ret[n:] - ret[:-n]
return ret[n - 1:] / n
def getCrossIndex(frame,sl,wh,sm,lineName,offset):
#crop ROI
band = frame[sl:sl+wh,:,0]
cv2.imshow(str(lineName),band)
#apply intial smooting to signal
roisum = band.sum(axis=0)/wh/255
roisum = [roisum[0]]*sm+list(moving_average(roisum,sm))[:-1]
#calculate cumulative avarage for light/dark segmentation
roiavg = list(np.cumsum(roisum)/np.arange(1,len(roisum)+1))
#get change amplitude
delta = np.subtract(roiavg, roisum)
#get meanAvg level of changes from light to dark
meanValue = max(delta[0:int(width)])/2
lines[lineName+"Avg"].set_ydata(list(np.asarray(roiavg)+offset))
lines[lineName+"AvgDelta"].set_ydata(list(np.asarray(delta)+offset))
lines[lineName+""].set_ydata(list(np.asarray(roisum)+offset))
lines[lineName+"meanAvg"].set_ydata(list(np.asarray([meanValue]*width)+offset))
i0 = 0
#find the first drastic change from light to dark
for i in range(len(delta)):
if delta[i] > meanValue:# and roisum[i]<roiavg[i]:
i0 = int(i-sm/2)
break
return i0
cv2.namedWindow('control')
def nothing(x):
pass
cv2.createTrackbar('wh','control',50,int(height/2),nothing)
cv2.createTrackbar('smooth','control',20,100,nothing)
cv2.createTrackbar('sliseoffset','control',0,100,nothing)
while True:
wh = max(cv2.getTrackbarPos('wh','control'),1)
smooth = max(cv2.getTrackbarPos('smooth','control'),1)
slizeoffset = max(cv2.getTrackbarPos('sliseoffset','control'),1)
slices = [{'index':slizeoffset,'name':'upper'},{'index':height-slizeoffset-wh,'name':'lower'}]
(grabbed, frame) = capture.read()
if not grabbed:
continue
frame = cv2.resize(frame, (width,height), interpolation = cv2.INTER_AREA)
coords = [{},{}]
i = 0
for _slice in slices:
offset = -1.5*slices.index(_slice)
i1 = width-getCrossIndex(cv2.flip(frame,1),_slice['index'],wh,smooth,_slice['name'],offset)
i0 = getCrossIndex(frame,_slice['index'],wh,smooth,_slice['name'],offset)
y = _slice['index']+wh/2
coords[i]['i0'] = i0
coords[i]['i1'] = i1
coords[i]['y'] = y
i = i+1
#calc angle and draw overlay
h = coords[1]['y']-coords[0]['y']
w = (coords[1]['i0']-coords[0]['i0'])
a = -math.atan(w/h)*180/3.14
if abs(a)<5:
cv2.putText(frame, "%.2f deg"%(a), (int((coords[1]['i0']+coords[0]['i0'])/2+10),int((coords[1]['y']+coords[0]['y'])/2)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255),1)
cv2.line(img=frame, pt1=(int(coords[0]['i0']), int(coords[0]['y'])), pt2=(int(coords[1]['i0']), int(coords[1]['y'])), thickness=2,color=(0, 255, 255))
for coord in coords:
i0 = coord['i0']
ii = coord['i1']
y = coord['y']
cv2.putText(frame, "%.2f mm"%((i1-i0)/50), (int(i1+10),int(y+5)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255),1)
cv2.circle(frame,center =(int(i0), int(y)), radius=10,thickness=3,color=(255, 0, 0))
cv2.circle(frame,center =(int(i1), int(y)), radius=10,thickness=3,color=(255, 0, 0))
cv2.line(img=frame, pt1=(int(i0), int(y)), pt2=(int(i1), int(y)), thickness=2,color=(255, 255, 255))
else:
cv2.putText(frame, "Not Found", (int(width/2),int(height/2)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255),1)
fig.canvas.draw()
img = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='')
img = img.reshape(fig.canvas.get_width_height()[::-1] + (3,))
img = cv2.cvtColor(img,cv2.COLOR_RGB2BGR)
cv2.imshow('chart',img)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
capture.release()
cv2.destroyAllWindows()

Related

Detecting Elliptical Shape in Noisy Image

I'm trying to detect the region here (circled in red) more effectively. As it currently stands, I have a few steps to get the area:
Brighten the input image
to increase contrast and likelihood to pick up edges of the image file to get this image
Crop and threshold the region of interest, and add Gaussian blur to get this image:
Use OpenCV to detect Hough Circles on the thresholded image
Select the top 10 largest circles found, then choose the one closest to the grid intersection (in the code as fv_cx and fv_cy) vertically and closest to the edge of the image horizontally.
While this works well in general
often times it misses the right circle
or it encircles an area too small
.
Using these input images, is there a better way to work on this problem?
This is my code so far:
from __future__ import print_function
import pandas as pd
from pandas.api.types import is_numeric_dtype
import os
from PIL import Image, ImageDraw, ImageFont
import math
import cv2
import matplotlib.pyplot as plt
import time
import re
import csv
from skimage import data, color, io, img_as_ubyte
from skimage.transform import hough_circle, hough_circle_peaks, hough_ellipse
from skimage.feature import canny
from skimage.draw import circle_perimeter, ellipse_perimeter
from skimage.util import img_as_ubyte
from builtins import input
import numpy as np
def append_list_as_row(file_name, list_of_elem):
with open(file_name, 'a+', newline='', encoding='utf-8') as write_obj:
csv_writer = csv.writer(write_obj, dialect='excel')
csv_writer.writerow(list_of_elem)
def round_up_to_odd(f):
return int(np.ceil(f) // 2 * 2 + 1)
# Folder path here
folder = r""
csv_file = folder + os.sep + "Measurements.csv"
csv_file2 = folder + os.sep + "Measurements2.csv"
df2 = pd.DataFrame(columns = ["filepath","od_cx","od_cy", "fv_x", "fv_y"])
for subdir, dirs, files in os.walk(folder):
for file in files:
#print os.path.join(subdir, file)
filepath = subdir + os.sep + file
if filepath.endswith(".jpeg") or filepath.endswith(".tiff") and not filepath.endswith("_OD.tiff") and not filepath.endswith("_bright.tiff") and not filepath.endswith("_FV.tiff") and not filepath.endswith("_mask.tiff"):
og_cv = cv2.imread(filepath, cv2.IMREAD_COLOR)
if "left" in str(filepath):
od = "left"
elif "right" in str(filepath):
od = "right"
OD_path = subdir + os.sep + "OD"
if not os.path.exists(str(OD_path)):
os.mkdir(str(OD_path))
OD = OD_path + os.sep + str(os.path.splitext(file)[0]) + "_OD.tiff"
fovea_path = OD_path + os.sep + str(os.path.splitext(file)[0]) + "_FV.tiff"
temp_path = subdir + os.sep + "Temp"
if not os.path.exists(str(temp_path)):
os.mkdir(str(temp_path))
bright = temp_path + os.sep + str(os.path.splitext(file)[0]) + "_bright.tiff"
thresholded_od = temp_path + os.sep + str(os.path.splitext(file)[0]) + "_thresholded_OD.tiff"
thresholded_fv = temp_path + os.sep + str(os.path.splitext(file)[0]) + "_thresholded_FV.tiff"
mask_file = temp_path + os.sep + str(os.path.splitext(file)[0]) + "_mask.tiff"
## Fovea
image = cv2.imread(filepath)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
h = image.shape[0]
w = image.shape[1]
# loop over the image
fv_cx = []
fv_cy = []
for y in range(0, h):
for x in range(0, w):
# threshold the pixel
if np.all(image[y, x] == (255, 0, 255)) and np.all(image[y, x+3] == (0, 255, 255)) and np.all(image[y, x-3] == (0, 255, 255)):
print("Found fovea")
fv_cx.append(x)
fv_cy.append(y)
# Draw them
# fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(10, 4))
# image = color.gray2rgb(image)
image_draw = image
if image.shape[2] == 3:
image[fv_cy, fv_cx] = (220, 20, 20)
if image.shape[2] == 4:
image[fv_cy, fv_cx] = (220, 20, 20, 0)
plt.imsave(OD, image)
print(fv_cx, fv_cy)
# else:
# fv_cx = "No fv_cx"
# fv_cy = "No fv_cy"
## Find image dimensions
source_img = Image.open(filepath)
width, height = source_img.size
x_max = int(width)
y_max = int(height)
print(x_max)
print(y_max)
#Load image
im = cv2.imread(filepath, cv2.IMREAD_COLOR)
background = Image.open(filepath).convert('RGB')
width, height = background.size
x_max = int(width)
y_max = int(height)
# Brightness adjustment - https://docs.opencv.org/3.4/d3/dc1/tutorial_basic_linear_transform.html
new_image = np.zeros(im.shape, im.dtype)
alpha = 1.0 # contrast control
beta = 0 # brightness control
new_image = cv2.convertScaleAbs(im, alpha=alpha, beta=100)
# cv2.imshow('New Image', new_image)
# cv2.waitKey(0)
cv2.imwrite(bright, new_image)
new_image = cv2.imread(bright, cv2.IMREAD_COLOR)
## OD
#Convert to HLS, so we can remove the saturated fovea
HLS = cv2.cvtColor(new_image,cv2.COLOR_BGR2HLS)
Schannel = HLS[:,:,2]
mask = cv2.inRange(Schannel, 0, 0)
# res = cv2.bitwise_and(new_image,new_image, mask= mask)
new_image = cv2.cvtColor(new_image,cv2.COLOR_BGR2GRAY)
thresh_x = round_up_to_odd((21/1033) * width)
thresh_x = 21
#### Thresholding Example Options
# img = cv2.bitwise_and(new_image,new_image, mask= mask)
img = cv2.medianBlur(new_image,5)
pil_im = Image.fromarray(mask)
# mask_width, mask_height = pil_im.size
mask_width, mask_height = (165 * (width/290)), (165 * (width/290))
print(width, height)
print(mask_width, mask_height)
margin = 10
if "_L" in filepath or "OS" in filepath:
x_center = width/2
crop_x_start = 0
crop_x_stop = int(x_center-(mask_width/2)) + margin
crop_img = img[0:height, crop_x_start:crop_x_stop]
# cv2.imshow("cropped", crop_img)
cv2.waitKey()
if "_R" in filepath or "OD" in filepath:
x_center = width/2
crop_x_start = int((x_center+(mask_width/2))) - margin
crop_x_stop = width
crop_img = img[0:height, crop_x_start:crop_x_stop]
# cv2.imshow("cropped", crop_img)
cv2.waitKey()
th2 = cv2.adaptiveThreshold(crop_img,255,cv2.ADAPTIVE_THRESH_MEAN_C,\
cv2.THRESH_BINARY,thresh_x,2)
th2 = cv2.GaussianBlur(th2,(21,21),0)
# cv2.imshow("cropped", th2)
cv2.waitKey()
cv2.imwrite(thresholded_od, th2)
## Hough Circle
# Load picture and detect edges
image = img_as_ubyte(th2)
edges = canny(image, sigma=3, low_threshold=10, high_threshold=50)
# Detect two radii
x=50
y=500
z=2
start = math.ceil((x/1033) * width)
stop = math.ceil((y/1033) * width)
step = math.ceil((z/1033) * width)
hough_radii = np.arange(start, stop, step)
hough_res = hough_circle(edges, hough_radii)
if fv_cy != []:
# Select the most prominent 3 circles
accums, cx, cy, radii = hough_circle_peaks(hough_res, hough_radii,
total_num_peaks=10)
df = pd.DataFrame(columns = ["index", "distance", "area", "cX", "cY"])
idx = (0)
# Draw them
fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(10, 4))
# image = color.gray2rgb(image)
image = io.imread(filepath)
cx = (cx + crop_x_start)
for center_y, center_x, radius in zip(cy, cx, radii):
# d = math.sqrt(((center_x-fv_cx)**2) + ((center_y-fv_cy)**2))
p = abs(center_y - fv_cy)
q = -1 * abs(center_x - fv_cx)
d = p + q
print(d)
area = math.pi * (radius**2)
df.loc[idx, 'index'] = idx
df.loc[idx, 'area'] = int(area)
df.loc[idx, 'distance'] = int(d)
df.loc[idx, 'cX'] = int(center_x)
df.loc[idx, 'cY'] = int(center_y)
df.loc[idx, 'radius'] = int(radius)
idx += 1
df['distance'] = pd.to_numeric(df['distance'])
df['radius'] = pd.to_numeric(df['radius'])
print("DF?")
print(df)
if len(df["distance"]) > 0:
print("pass")
df_radius = df.nsmallest(3, 'distance')
print(df_radius)
if (df_radius['radius'].max()-df_radius['radius'].min()) < 3:
idx = df_radius['radius'].idxmax()
else:
idx = df['distance'].idxmin()
center_y = int(df.loc[idx, 'cY'])
center_x = int(df.loc[idx, 'cX'])
radius = int(df.loc[idx, 'radius'])
print(center_y, center_x, radius)
# Draw them
# fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(10, 4))
# image = color.gray2rgb(image)
image = io.imread(filepath)
image = image_draw
circy, circx = circle_perimeter(center_y, center_x, radius,
shape=image.shape)
print(image.shape)
print(image.shape[2])
if image.shape[2] == 3:
image_draw[circy, circx] = (220, 20, 20)
circy, circx = circle_perimeter(center_y, center_x, 0,
shape=image.shape)
image_draw[circy, circx] = (220, 20, 20)
if image.shape[2] == 4:
image_draw[circy, circx] = (220, 20, 20, 0)
circy, circx = circle_perimeter(center_y, center_x, 0,
shape=image.shape)
image_draw[circy, circx] = (220, 20, 20, 0)
# final = ax.imshow(image, cmap=plt.cm.gray)
# fig = plt.show()
## Need to fix saving
plt.imsave(OD, image_draw)
else:
hough_radii = np.arange(start, stop, step)
hough_res = hough_circle(edges, hough_radii)
# Select the most prominent 3 circles
accums, cx, cy, radii = hough_circle_peaks(hough_res, hough_radii,
total_num_peaks=1)
if cx != None:
print("Found OD")
od_cx = (re.search(r"\[([A-Za-z0-9_]+)\]",str(cx))).group(1)
od_cy = (re.search(r"\[([A-Za-z0-9_]+)\]",str(cy))).group(1)
else:
od_cx = "Not found"
od_cy = "Not found"
# Draw them
#fig, ax = plt.subplots(ncols=1, nrows=1, #figsize=(10, 4))
# image = color.gray2rgb(image)
image = io.imread(filepath)
image = image_draw
for center_y, center_x, radius in zip(cy, cx, radii):
circy, circx = circle_perimeter(center_y, center_x, radius,
shape=image.shape)
print(image.shape)
print(image.shape[2])
if image.shape[2] == 3:
image_draw[circy, circx] = (220, 20, 20)
circy, circx = circle_perimeter(center_y, center_x, 0,
shape=image.shape)
image_draw[circy, circx] = (220, 20, 20)
if image.shape[2] == 4:
image_draw[circy, circx] = (220, 20, 20, 0)
circy, circx = circle_perimeter(center_y, center_x, 0,
shape=image.shape)
image_draw[circy, circx] = (220, 20, 20, 0)
# final = ax.imshow(image, cmap=plt.cm.gray)
# fig = plt.show()
## Need to fix saving
plt.imsave(OD, image_draw)
append_list_as_row(csv_file,[filepath,center_x,center_y, fv_cx, fv_cy])
plt.close('all')
df2 = df2.append({"filepath":filepath,"od_cx":center_x, "od_cy":center_y, "fv_x":fv_cx, "fv_y":fv_cy}, ignore_index=True)
print(df2)
df2.to_csv(csv_file2)

How to Avoid Killed:9 message

I have a list with length 37500 in my code. However, when I try to assign that list to a dictionary slot, I get the VSCode error, Killed:9. Is there any way to avoid this? Here is my code:
#The testing image naturally has a grey linein the middle
from PIL import Image, ImageOps
import numpy as np
from pathlib import Path
import matplotlib.pyplot as plt
import pickle
import time
import os
mod_path = Path(__file__).parent
input_dirImage = os.listdir((mod_path / "Images").resolve())
imput_dirGround = os.listdir((mod_path / "groundTruth").resolve())
len_images = len(input_dirImage)
size = (650,650) #Size of the ROI
fitSize = (900,800) #Size to change the original Image to before ROI
start_time = time.time() #starting the timer
ROIList = [] #Array that holds the ROI grayscale values
covidList = [] #Whether the ROI is covid positive or negative
groundList = [] #Array that holds the ROI groundtruth true or false values
for image in input_dirImage[0:len_images]:
if image == '.DS_Store':
continue
parent_path = Path(__file__).parent
secondDirImage = (mod_path / "Images" / image).resolve() #Path of the covid image
secondDirGround = groundTruthDir = (mod_path / "groundTruth" / "fourPositive_b&w.tif").resolve() #Path of the ground truth
image = Image.open(str(secondDirImage))
ground = Image.open(str(secondDirGround))
image = ImageOps.fit(image, fitSize, Image.ANTIALIAS)
ground = ImageOps.fit(ground, fitSize, Image.ANTIALIAS)
xBias = 0
yBias = 0
while(yBias + size[1] <= fitSize[1]):
crop_rectangle = (xBias, yBias, xBias + size[0], yBias + size[1])
ROIList.append(np.mean(np.array(image.crop(crop_rectangle)),axis = 2))
tempGround = np.mean(np.array(ground.crop(crop_rectangle)),axis = 2)
count = 0
# print(tempGround.size)
# print(np.array(ground.crop(crop_rectangle)).shape)
# print(np.mean(np.array(ground.crop(crop_rectangle)),axis = 2).shape)
# for i in range(0,tempGround.shape[0]):
# for j in range(0,tempGround.shape[1]):
# if tempGround[i][j] > 50:
# count+=1
# print(count)
tempGround[tempGround<50.0] = False
tempGround[tempGround>240.0] = True #All values greater than 240 become true. Are in this order because otherwise
# print(np.count_nonzero(tempGround))
groundList.append(tempGround)
# plt.imshow(np.mean(image.crop(crop_rectangle),axis = 2),cmap = "gray", vmin = 0, vmax = 255)
# plt.show(block = False)
# plt.pause(.2)
# plt.close()
# plt.imshow(np.mean(ground.crop(crop_rectangle),axis = 2),cmap = "gray", vmin = 0, vmax = 255)
# plt.show(block = False)
# plt.pause(.2)
# plt.close()
if(xBias + size[0] == fitSize[0]): #Only need to check the image's status, as the image and the ground have the same dimensions
yBias += 1
xBias = 0
print("dang")
else:
xBias +=1
dictionary = dict()
dictionary['image'] = ROIList
dictionary['ground'] = groundList
print("yo")
print(np.count_nonzero(dictionary['ground']))
print(len(dictionary['ground']))
plt.imshow(dictionary['image'][105], cmap = "gray", vmin = 0, vmax = 255)
plt.show()
plt.imshow(dictionary['ground'][105], cmap = "gray", vmin = 0, vmax = 1)
plt.show()
plt.imshow(dictionary['image'][200], cmap = "gray", vmin = 0, vmax = 255)
plt.show()
plt.imshow(dictionary['ground'][200], cmap = "gray", vmin = 0, vmax = 1)
plt.show()
plt.imshow(dictionary['image'][205], cmap = "gray", vmin = 0, vmax = 255)
plt.show()
plt.imshow(dictionary['ground'][205], cmap = "gray", vmin = 0, vmax = 1)
plt.show()
plt.imshow(dictionary['image'][150], cmap = "gray", vmin = 0, vmax = 255)
plt.show()
plt.imshow(dictionary['ground'][150], cmap = "gray", vmin = 0, vmax = 1)
plt.show()
with open((mod_path / 'imageOne.pickle').resolve(),'wb') as handle:
pickle.dump(dictionary, handle, protocol = pickle.HIGHEST_PROTOCOL)
print("Process finished --- %s seconds ---" % (time.time() - start_time))
I understand this error message is result of a lack of memory, would assigning the data to the dictionary gradually help this at all?

Animate label with bar chart - matplotlib

The code below animates a bar chart and associated label values. The issue I'm having is positioning the label when the integer is negative. Specifically, I want the label to be positioned on top of the bar, not inside it. It's working for the first frame but the subsequent frames of animation revert back to plotting the label inside the bar chart for negative integers.
def autolabel(rects, ax):
# Get y-axis height to calculate label position from.
ts = []
(y_bottom, y_top) = ax.get_ylim()
y_height = y_top - y_bottom
for rect in rects:
height = 0
if rect.get_y() < 0:
height = rect.get_y()
else:
height = rect.get_height()
p_height = (height / y_height)
if p_height > 0.95:
label_position = height - (y_height * 0.05) if (height > -0.01) else height + (y_height * 0.05)
else:
label_position = height + (y_height * 0.01) if (height > -0.01) else height - (y_height * 0.05)
t = ax.text(rect.get_x() + rect.get_width() / 2., label_position,
'%d' % int(height),
ha='center', va='bottom')
ts.append(t)
return ts
def gradientbars(bars, ax, cmap, vmin, vmax):
g = np.linspace(vmin,vmax,100)
grad = np.vstack([g,g]).T
xmin,xmax = ax.get_xlim()
ymin,ymax = ax.get_ylim()
ims = []
for bar in bars:
bar.set_facecolor('none')
im = ax.imshow(grad, aspect="auto", zorder=0, cmap=cmap, vmin=vmin, vmax=vmax, extent=(xmin,xmax,ymin,ymax))
im.set_clip_path(bar)
ims.append(im)
return ims
vmin = -6
vmax = 6
cmap = 'PRGn'
data = np.random.randint(-5,5, size=(10, 4))
x = [chr(ord('A')+i) for i in range(4)]
fig, ax = plt.subplots()
ax.grid(False)
ax.set_ylim(vmin, vmax)
rects = ax.bar(x,data[0])
labels = autolabel(rects, ax)
imgs = gradientbars(rects, ax, cmap=cmap, vmin=vmin, vmax=vmax)
def animate(i):
for rect,label,img,yi in zip(rects, labels, imgs, data[i]):
rect.set_height(yi)
label.set_text('%d'%int(yi))
label.set_y(yi)
img.set_clip_path(rect)
anim = animation.FuncAnimation(fig, animate, frames = len(data), interval = 500)
plt.show()
It's working for the first frame.
You call autolabel(rects, ax) in the first plot, so the label is well placed.
The subsequent frames of animation revert back to plotting the label inside the bar chart for negative integers.
The label position of subsequent frames is set by label.set_y(yi). yi is from data[i], you didn't consider the negative value here.
I create a function named get_label_position(height) to calculate the right label position for give height. It uses a global variable y_height. And call this function before label.set_y().
import matplotlib.pyplot as plt
from matplotlib import animation
import pandas as pd
import numpy as np
def get_label_position(height):
p_height = (height / y_height)
label_position = 0
if p_height > 0.95:
label_position = height - (y_height * 0.05) if (height > -0.01) else height + (y_height * 0.05)
else:
label_position = height + (y_height * 0.01) if (height > -0.01) else height - (y_height * 0.05)
return label_position
def autolabel(rects, ax):
# Get y-axis height to calculate label position from.
ts = []
(y_bottom, y_top) = ax.get_ylim()
y_height = y_top - y_bottom
for rect in rects:
height = 0
if rect.get_y() < 0:
height = rect.get_y()
else:
height = rect.get_height()
p_height = (height / y_height)
if p_height > 0.95:
label_position = height - (y_height * 0.05) if (height > -0.01) else height + (y_height * 0.05)
else:
label_position = height + (y_height * 0.01) if (height > -0.01) else height - (y_height * 0.05)
t = ax.text(rect.get_x() + rect.get_width() / 2., label_position,
'%d' % int(height),
ha='center', va='bottom')
ts.append(t)
return ts
def gradientbars(bars, ax, cmap, vmin, vmax):
g = np.linspace(vmin,vmax,100)
grad = np.vstack([g,g]).T
xmin,xmax = ax.get_xlim()
ymin,ymax = ax.get_ylim()
ims = []
for bar in bars:
bar.set_facecolor('none')
im = ax.imshow(grad, aspect="auto", zorder=0, cmap=cmap, vmin=vmin, vmax=vmax, extent=(xmin,xmax,ymin,ymax))
im.set_clip_path(bar)
ims.append(im)
return ims
vmin = -6
vmax = 6
cmap = 'PRGn'
data = np.random.randint(-5,5, size=(10, 4))
x = [chr(ord('A')+i) for i in range(4)]
fig, ax = plt.subplots()
ax.grid(False)
ax.set_ylim(vmin, vmax)
rects = ax.bar(x,data[0])
labels = autolabel(rects, ax)
imgs = gradientbars(rects, ax, cmap=cmap, vmin=vmin, vmax=vmax)
(y_bottom, y_top) = ax.get_ylim()
y_height = y_top - y_bottom
def animate(i):
for rect,label,img,yi in zip(rects, labels, imgs, data[i]):
rect.set_height(yi)
label.set_text('%d'%int(yi))
label.set_y(get_label_position(yi))
img.set_clip_path(rect)
anim = animation.FuncAnimation(fig, animate, frames = len(data), interval = 500)
plt.show()

Streaming to website instead of Window OpenCV

Human Recogition Program
class PeopleTracker:
hog = cv2.HOGDescriptor()
caps = cv2.VideoCapture(r'C:/Users/Emyr/Documents/Jupyter/pedestrian-detection/video/Ped4.MOV')
count = int(caps.get(cv2.CAP_PROP_FRAME_COUNT))
center = []
recCount = 0
pick = 0
# Red Yellow Blue Green Purple
colors = [(255,0,0),(255,255,0),(0,0,255),(0,128,0),(128,0,128)]
def BBoxes(self, frame):
#frame = imutils.resize(frame, width = min(frame.shape[0], frame.shape[1]))
frame = imutils.resize(frame, width= 1000,height = 1000)
# detect people in the image
(rects, weights) = self.hog.detectMultiScale(frame, winStride=(1,1), padding=(3, 3), scale=0.5)
# apply non-maxima suppression to the bounding boxes using a
# fairly large overlap threshold to try to maintain overlapping
# boxes that are still people
rects = np.array([[x, y, x + w, y + h] for (x, y, w, h) in rects])
self.pick = non_max_suppression(rects, probs=None, overlapThresh=0.7)
# draw the final bounding boxes
self.recCount = 0
for (xA, yA, xB, yB) in self.pick:
#cv2.rectangle(frame, (xA, yA), (xB, yB), (0, 255, 0), 2)
CentxPos = int((xA + xB)/2)
CentyPos = int((yA + yB)/2)
cv2.circle(frame,(CentxPos, CentyPos), 5, (0,255,0), -1)
self.recCount += 1
if len(rects) >1:
self.center.append([CentxPos, CentyPos])
return frame
def Clustering(self, frame):
db = DBSCAN(eps= 70, min_samples = 2).fit(self.center)
labels = db.labels_
# Number of clusters in labels, ignoring noise if present.
n_clusters_ = len(set(labels)) - (1 if -1 in labels else 0)
n_noise_ = list(labels).count(-1)
#print("Labels: ", labels)
# Black removed and is used for noise instead.
unique_labels = set(labels)
#print("Unique Labels: ", unique_labels)
#colors = plt.cm.rainbow(np.linspace(0, 255, len(unique_labels)))
#colors = [(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) for k in range(len(unique_labels)) ]
#print(self.colors)
i = 0
for (xA, yA, xB, yB) in self.pick:
if labels[i] == -1:
cv2.rectangle(frame, (xA, yA), (xB, yB), (0, 0, 0), 2)
i += 1
else:
cv2.rectangle(frame, (xA, yA), (xB, yB), (self.colors[labels[i]][0], self.colors[labels[i]][1], self.colors[labels[i]][2]), 2)
i += 1
#print("Colours: ", colors)
center = np.asarray(self.center)
#fig, ax = plt.subplots()
#ax.set_xlim(0,frame.shape[1])
#ax.set_ylim(frame.shape[0], 0)
#for k, col in zip(unique_labels, colors):
#if k == -1:
#Black used for noise.
#col = [0, 0, 0, 1]
#class_member_mask = (labels == k)
#xy = center[class_member_mask]
#plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=tuple(col), markeredgecolor='k', markersize=8)
def main():
PT = PeopleTracker()
PT.hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())
while PT.count > 1:
PT.center = []
ret, frame = PT.caps.read()
frame = PT.BBoxes(frame)
if PT.recCount >= 2:
PT.Clustering(frame)
#plt.title('Estimated number of clusters: %d' % n_clusters_)
#plt.show()
cv2.imshow("Tracker", frame)
cv2.waitKey(1)
#cv2.destroyAllWindows()
PT.count = PT.count - 1
else:
cv2.imshow("Tracker", frame)
cv2.waitKey(1)
#cv2.destroyAllWindows()
PT.count = PT.count - 1
The code I currently have here displays the stream of an existing human recognition video to a window (as shown in the picture in the link), if possible I was wondering is there a way in which I can send that video feed to a website that im developing instead of using a window?
Thank You in advance :)
I have it semi-working, I ended up using flask but the problem is that im displaying the original video not the one produced by opencv i was wondering if anyone had any ideas on how i could implement the prior code into this? and use the "frame" variable for the video feed
from flask import Flask, render_template, Response
import cv2
import sys
import numpy
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
def gen():
i=1
while i < 10:
yield (b'--frame\r\n'b'Content-Type: text/plain\r\n\r\n'+str(i)+b'\r\n')
i+=1
def get_frame():
ramp_frames=100
camera=cv2.VideoCapture('IMG_2649.MOV')
i=1
while True:
retval, im = camera.read()
imgencode=cv2.imencode('.jpg',im)[1]
stringData=imgencode.tostring()
yield (b'--frame\r\n'
b'Content-Type: text/plain\r\n\r\n'+stringData+b'\r\n')
i+=1
del(camera)
#app.route('/calc')
def calc():
return Response(get_frame(),mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == '__main__':
app.run(host='localhost', debug=True, threaded=True)
HTML Code
<html>
<head>
<title>Video Streaming Demonstration</title>
</head>
<body>
<h1>Video Streaming Demonstration</h1>
<img src="{{ url_for('calc') }}">
<!-- <h1>{{ url_for('calc') }}</h1> -->
</body>
</html>

update matplotlib path interactively on figure and extract actual data for recalculation

I have a plot where I want to interactively adjust the position of a patch and use the interactive update to be used in recalculating a variable.
I have plotted and image and added a closed contour (represented using PathPatch)
Here is an example image. example image with contour where information is calculated from the pixels enclosed by the contour. The pixel mask needs to be updated so that plots on right can also be updated.
Currently I plot everything and then use an event to move the contour, I tried using transforms and this worked to move the contour but when I tried using the transform to update the binary mask needed to recalculate the plots on the right side, the transformation it returns is incorrect. On top of this the transforms caused the contour to move when zooming in and out from the interactive window.
I need to figure out how to shift the contour and re-plot it and then extract the shift and apply to extracting a new mask of enclosed points to update the calculation.
import matplotlib.pyplot as plt
import matplotlib as mpl
import matplotlib.path as mplpath
import matplotlib.patches as patches
from matplotlib.widgets import Button, Slider
# GENERATE SOME DATA TO PLOT
# event functions
def press(event):
print('press', event.key)
sys.stdout.flush()
if (event.key == 'left'):
shift[0] -= 1.0
elif (event.key == 'right'):
shift[0] += 1.0
elif (event.key == 'up'):
shift[1] += 1
elif (event.key == "down"):
shift[1] -= 1.0
# this is where I don't know how to properly transform and update[!
fig.canvas.draw()
class Recalculate(object):
def update(self, event):
x_update = [x_ for x_ in x_pts]
y_update = [y_ for y_ in y_pts]
verts_test = np.column_stack((x_update, y_update))
new_contour = mplpath.Path(verts_test, closed=True)
# create mask
new_grid = getMask(im_vol_resize, new_contour)
# calculate the flow
q_sum = []
for i in range(N): #assume size doesn't change
q_mask_sum = np.sum(test_q[:,:,i]*new_grid.astype(image_dtype))
q_sum.append(q_mask_sum*np.prod(spacing[0:2])/(100.0*scale**2)) # cm^3
print("total flow {0} cm^3/beat".format(np.trapz( q_sum, dx = np.mean(mean_diff)/1000)))
q_sum_roll = np.roll(q_sum, -16)
#q_interp = interpolate.CubicSpline(new_time, q_sum_roll, bc_type='periodic')
q_interp = interpolate.InterpolatedUnivariateSpline(new_time, q_sum_roll, k=3, ext=0)
q_test = q_interp(t_interp)
#plotting update
grid_handle.set_data(new_grid)
#print(new_time)
scat_data = np.stack((new_time, q_sum), axis=1)
#ax2.relim() # make sure all the data fits
#ax2.autoscale()
#print(scat_data.shape)
scatter_handle.set_offsets(scat_data)
interp_handle[-1].set_ydata(q_test)
ax3.relim() # make sure all the data fits
ax3.autoscale()
ax2.set_xlim(ax3.get_xlim())
ax2.set_ylim(ax3.get_ylim())
fig.canvas.draw()
def update_cine(val):
ind = int(slider.val)
s = [slice(ind, ind + 1) if i == 2 else slice(None)
for i in range(3)]
for sd in xyz_keys:
im = cubes[sd][s].squeeze()
cine_ax_dict[sd].set_data(im)
ax6.set_title("time: {0}".format(new_time[ind]))
ax2.scatter(new_time, q_sum, c='b', label='flowRate')
ax2.scatter(new_time[ind], q_sum[ind], c='r', label='time={0}'.format(new_time[ind]))
fig.canvas.draw()
#figures
gs = plt.GridSpec(6, 6, wspace=0.2, hspace=0.2)
fig = plt.figure(figsize=(17, 9))
fig.canvas.mpl_connect('key_press_event', press)
ax = fig.add_subplot(gs[3:,0:3])
#xl = ax.set_xlabel('easy come, easy go')
#ax.set_title('Press a key')
patch = patches.PathPatch(contour, facecolor=(1.0,165./255.0,0,0.25), lw=1 )#, alpha=0.5)
patch_handle = ax.add_patch(patch)
#plt.plot(x_pts, y_pts)
x_bounds = [round((bounds[0]-4)*scale), round((bounds[1]+4)*scale)]
y_bounds = [round((bounds[2]-4)*scale), round((bounds[3]+4)*scale)]
ax.set_xlim(x_bounds)
ax.set_ylim(y_bounds)
ax.imshow(im_vol_resize, interpolation='bilinear', cmap="gray", alpha=1.0)
ax5 = fig.add_subplot(gs[0:3,0:3])
patch2 = patches.PathPatch(contour, facecolor='none', linewidth=0.8, edgecolor=(1.0,165./255.0,0,0.50))#, alpha=0.5)
ax5.imshow(im_vol_resize, interpolation='bilinear', cmap="gray", alpha=1.0)
patch_handle2 = ax5.add_patch(patch2)
#new_contour = patch_.get_path()
ax5.set_xlim(x_bounds)
ax5.set_ylim(y_bounds)
# show ROI mask
grid_handle = ax.imshow(grid, interpolation='None', cmap="gray", alpha=0.1)
#print(dir(grid_handle))
ax2 = fig.add_subplot(gs[0:3, 4:])
scatter_handle = ax2.scatter(new_time, q_sum, c='b', label='flowRate')
ax2.scatter(new_time[0], q_sum[0], c='r', label='cine time')
#print(dir(scatter_handle))
#ax2.scatter(dict_time["y"], q_sum, label='flowRatey')
#ax2.scatter(dict_time["z"], q_sum, label='flowRatez')
#ax2.plot(dict_time["x"], q_sum)
#ax2.set_xlabel(r'$t$', fontsize=20)
ax2.set_title('terminal ICA Waveform', fontsize=20)
ax2.set_ylabel(r'Q, $Q(t)$ $cm^3/min$', fontsize=20)
ax2.xaxis.set_ticks_position('none')
ax2.xaxis.set_ticklabels([])
ax2.legend(loc='center left', bbox_to_anchor=(1, 0.9))
ax3 = fig.add_subplot(gs[3:, 4:])
ax3.set_xlabel(r'time $t$ $milliseconds$', fontsize=20)
ax3.set_ylabel(r'Flowrate $cm^3/min$', fontsize=20)
ax3.set_xlim(ax2.get_xlim())
ax3.set_ylim(ax2.get_ylim())
interp_handle = ax3.plot(t_interp, q_test, c='b', linestyle='-', label='interp')
#print(dir(interp_handle[0]))
ax3.legend(loc='center left', bbox_to_anchor=(1, 0.9))
cine_ax_dict = {}
ax6 = fig.add_subplot(gs[0:2,2:4])
ax6.set_title("time: {0}".format(new_time[0]))
cine_ax_dict["x"] = ax6.imshow(cubes['x'][:,:,0], interpolation='bilinear', cmap="viridis", alpha=1.0)
patch6 = patches.PathPatch(contour, facecolor='none', linewidth=0.8, edgecolor=(1.0,165./255.0,0,0.50))
ax6.add_patch(patch6)
ax6.set_xlim(x_bounds)
ax6.set_ylim(y_bounds)
ax7 = fig.add_subplot(gs[2:4,2:4])
cine_ax_dict["y"] = ax7.imshow(cubes['y'][:,:,0], interpolation='bilinear', cmap="viridis", alpha=1.0)
patch7 = patches.PathPatch(contour, facecolor='none', linewidth=0.8, edgecolor=(1.0,165./255.0,0,0.50))
ax7.add_patch(patch7)
ax7.set_xlim(x_bounds)
ax7.set_ylim(y_bounds)
ax8 = fig.add_subplot(gs[4:,2:4])
cine_ax_dict["z"] = ax8.imshow(cubes['z'][:,:,0], interpolation='bilinear', cmap="viridis", alpha=1.0)
patch8 = patches.PathPatch(contour, facecolor='none', linewidth=0.8, edgecolor=(1.0,165./255.0,0,0.50))
ax8.add_patch(patch8)
ax8.set_xlim(x_bounds)
ax8.set_ylim(y_bounds)
# define slider
axcolor = 'lightslategray'
ax_c = fig.add_axes([0.25, 0.05, 0.60, 0.03], aspect="auto", facecolor=axcolor)
slider = Slider(ax_c, 'Axis %i index' % 2, 0, cubes["x"].shape[2] - 1,
valinit=0, valfmt='%i')

Categories

Resources