I am trying to execute a while loop that holds a function with parameters. However, I have noticed that the parameters inside the while loop are not updated which leads to an infinite while loop. Is there a reason behind the fact that the function parameters are not being updated after every loop?
import shapefile
from osgeo import gdal
#import rasterio
print (gdal.VersionInfo())
def pointInRect(x, y, x1, y1, w, h): # check if a raster point is in another raster
x2, y2 = x1+w, y1+h
if (x1 < x and x < x2):
if (y1 < y and y < y2):
return True
return False
# Open the shapes centroids
shp_cntrds = 'Path to centroids'
sf_cntrds = shapefile.Reader(shp_cntrds)
shapes_cntrds = sf_cntrds.shapes()
records_cntrds = sf_cntrds.records()
# adjust labels position according to its shapes centroids position
for i in range(len(records_cntrds)):
print(i)
tods = gdal.Open(str(records_cntrds[i][1]))
width = tods.RasterXSize
height = tods.RasterYSize
tods.SetGeoTransform([shapes_cntrds[i].points[0][0] - (width * 0.005), 0.01, 0,
shapes_cntrds[i].points[0][1] + (height * 0.005), 0, -0.01])
gt = tods.GetGeoTransform()
left = gt[0]
bottom = gt[3] + width * gt[4] + height * gt[5]
right = gt[0] + width * gt[1] + height * gt[2]
top = gt[3]
srs = osr.SpatialReference()
srs.SetUTM(32, 1) # set crs
srs.SetWellKnownGeogCS('WGS84') # set crs
tods.SetProjection(srs.ExportToWkt()) # set Projection and save file
print(width, height)
tods = None
# iterate through Labels and move labels away from each others if they overlapp
for i in range(len(records_cntrds)):
tods1 = gdal.Open(str(records_cntrds[i][1])) # records of the centroid shapefile contains the raster file path
width = tods1.RasterXSize
height = tods1.RasterYSize
gt = tods1.GetGeoTransform()
left = gt[0]
bottom = gt[3] + width * gt[4] + height * gt[5]
right = gt[0] + width * gt[1] + height * gt[2]
top = gt[3]
face = [x for x in list(range(len(records_cntrds))) if x != i]
tods1 = None
for j in face:
if str(records_cntrds[i][1]) == str(records_cntrds[j][1]):
pass
else:
ds_raster_face = gdal.Open(str(records_cntrds[j][1]))
#print(str(records_cntrds[i][1]))
#print(str(records_cntrds[j][1]))
gt_face = ds_raster_face.GetGeoTransform()
width_face = ds_raster_face.RasterXSize
height_face = ds_raster_face.RasterYSize
left_face = gt_face[0]
bottom_face = gt_face[3] + width_face * gt_face[4] + height_face * gt_face[5]
right_face = gt_face[0] + width_face * gt_face[1] + height_face * gt_face[2]
top_face = gt_face[3]
width1 = width
left1 = left
height1 = height
bottom1 = bottom
while pointInRect(left_face, bottom_face, left1, bottom1, width1*0.01, height1*0.01) :
tods2 = gdal.Open(str(records_cntrds[i][1]))
gt = tods2.GetGeoTransform()
width1 = tods2.RasterXSize
height1 = tods2.RasterYSize
left1 = gt[0]
bottom1 = gt[3] + width1 * gt[4] + height1 * gt[5]
print("while executed")
tods2.SetGeoTransform([(shapes_cntrds[i].points[0][0] - (width1 * 0.005)) - 2.7, 0.01, 0,
(shapes_cntrds[i].points[0][1] + (height1 * 0.005)) - 2.8, 0, -0.01])
print("coordinates changed to",(i, left1, bottom1, width1, height1))
tods2 = None
The while loop should break when the function return false but it is repeating the same thing. Are the gt values not updatet or are they initialized again ?
The following animates a circle and lines based on a given radius. I'm hoping combine the plot with animated text highlighting different segments within this circle. The text does get updated for each new frame but it doesn't remove the previous frames text.
Note: I'm trying to keep the animate function as I want to keep the axis the same and only animate updated data.
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import animation
import matplotlib.gridspec as gridspec
import math
df = pd.DataFrame({
'Time' : [1,1,1,1,2,2,2,2,3,3,3,3],
'X2' : [0,0,0,0,-1,-1,-1,-1,0,0,0,0],
'Y2' : [0,0,0,0,1,1,1,1,1,1,1,1],
'Angle' : [0,0,0,0,-45,-45,-45,-45,90,90,90,90],
})
fig = plt.figure(figsize = (8,10))
grid = gridspec.GridSpec(1, 2)
gridsize = (1, 2)
ax = plt.subplot2grid(gridsize, (0, 0))
ax2 = plt.subplot2grid(gridsize, (0, 1))
ax2.set_xlim(-10, 10)
ax2.set_ylim(-10, 10)
# the center of the compass
moving_x = np.array(df.groupby(['Time'])['X2'].apply(list))
moving_y = np.array(df.groupby(['Time'])['Y2'].apply(list))
moving_point = ax.scatter(moving_x[0], moving_y[0], c = 'black', marker = 'o', zorder = 3)
radius = df.drop_duplicates(subset = ['Time','X2', 'Y2'])[['X2', 'Y2']].values
circle = plt.Circle(radius[0], 10, color = 'black', fill = False, lw = 0.2)
circle2 = plt.Circle(radius[0], 10, color = 'red', fill = False, lw = 0.2)
ax.add_patch(circle)
ax2.add_patch(circle2)
line1, = ax.plot([],[], color = 'k', linewidth = 1)
line2, = ax.plot([],[], color = 'k', linewidth = 1)
t = df['Angle'][0]
angles = np.array(df.groupby(['Time'])['Angle'].apply(list))
angleText = df.drop_duplicates(subset = ['Time','Angle'])['Angle'].values
rot_mat = lambda theta:np.array([
[np.cos(np.deg2rad(theta)),-np.sin(np.deg2rad(theta))],
[np.sin(np.deg2rad(theta)),np.cos(np.deg2rad(theta))]
])
# compass tags
annotate_tags = ['N','E','S','W']
def animate(i) :
moving_point.set_offsets(np.c_[moving_x[0+i], moving_y[0+i]])
circle.center = (radius[i,0], radius[i,1])
xs1L1=-10.0/2**0.5
ys1L1=10.0/2**0.5
xs2L1=10.0/2**0.5
ys2L1=-10.0/2**0.5
xs1L2=-xs1L1
ys1L2=ys1L1
xs2L2=-xs1L2
ys2L2=ys2L1
cx=radius[i,0]
cy=radius[i,1]
theta=math.radians(angles[i][0])
x1L1=( (xs1L1+radius[i,0] - cx) * math.cos(theta) + (ys1L1+radius[i,1] - cy) * math.sin(theta) ) + cx
x2L1=( (xs2L1+radius[i,0] - cx) * math.cos(theta) + (ys2L1+radius[i,1]- cy) * math.sin(theta) ) + cx
y1L1=( -(xs1L1+radius[i,0] - cx) * math.sin(theta) + (ys1L1+radius[i,1] - cy) * math.cos(theta) ) + cy
y2L1=( -(xs2L1+radius[i,0] - cx) * math.sin(theta) + (ys2L1+radius[i,1] - cy) * math.cos(theta) ) + cy
line1.set_data([x1L1,x2L1],[y1L1,y2L1])
x1L2=( (xs1L2+radius[i,0] - cx) * math.cos(theta) + (ys1L2+radius[i,1] - cy) * math.sin(theta) ) + cx
x2L2=( (xs2L2+radius[i,0] - cx) * math.cos(theta) + (ys2L2+radius[i,1]- cy) * math.sin(theta) ) + cx
y1L2=( -(xs1L2+radius[i,0] - cx) * math.sin(theta) + (ys1L2+radius[i,1] - cy) * math.cos(theta) ) + cy
y2L2=( -(xs2L2+radius[i,0] - cx) * math.sin(theta) + (ys2L2+radius[i,1] - cy) * math.cos(theta) ) + cy
line2.set_data([x1L2,x2L2],[y1L2,y2L2])
# Animate compass tags for each frame
tag_pos = np.array([[0,8.5],[8.5,0],[0,-8.5],[-8.5,0]])
tag_pos = tag_pos # rot_mat(angleText[i])
for tag,pos in zip(annotate_tags,tag_pos):
ax.annotate(tag,xy=pos+radius[i], xycoords='data',
fontsize=10,horizontalalignment='right', verticalalignment='bottom')
ani = animation.FuncAnimation(fig, animate, np.arange(0,3), blit = False)
You want to create text objects for as many tags outside the animate function. And, inside the animate function set_text and set_position as shown here:
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import animation
import matplotlib.gridspec as gridspec
import math
df = pd.DataFrame({
'Time' : [1,1,1,1,2,2,2,2,3,3,3,3],
'X2' : [0,0,0,0,-1,-1,-1,-1,0,0,0,0],
'Y2' : [0,0,0,0,1,1,1,1,1,1,1,1],
'Angle' : [0,0,0,0,-45,-45,-45,-45,90,90,90,90],
})
fig = plt.figure(figsize = (20,10))
grid = gridspec.GridSpec(1, 2)
gridsize = (1, 2)
ax = plt.subplot2grid(gridsize, (0, 0))
ax2 = plt.subplot2grid(gridsize, (0, 1))
ax2.set_xlim(-10, 10)
ax2.set_ylim(-10, 10)
# the center of the compass
moving_x = np.array(df.groupby(['Time'])['X2'].apply(list))
moving_y = np.array(df.groupby(['Time'])['Y2'].apply(list))
moving_point = ax.scatter(moving_x[0], moving_y[0], c = 'black', marker = 'o', zorder = 3)
radius = df.drop_duplicates(subset = ['Time','X2', 'Y2'])[['X2', 'Y2']].values
circle = plt.Circle(radius[0], 10, color = 'black', fill = False, lw = 0.2)
circle2 = plt.Circle(radius[0], 10, color = 'red', fill = False, lw = 0.2)
ax.add_patch(circle)
ax2.add_patch(circle2)
line1, = ax.plot([],[], color = 'k', linewidth = 1)
line2, = ax.plot([],[], color = 'k', linewidth = 1)
t = df['Angle'][0]
angles = np.array(df.groupby(['Time'])['Angle'].apply(list))
angleText = df.drop_duplicates(subset = ['Time','Angle'])['Angle'].values
rot_mat = lambda theta:np.array([
[np.cos(np.deg2rad(theta)),-np.sin(np.deg2rad(theta))],
[np.sin(np.deg2rad(theta)),np.cos(np.deg2rad(theta))]
])
# compass tags
annotate_tags = ['N','E','S','W']
annotation=[None]*len(annotate_tags)
for i in range(len(annotate_tags)):
annotation[i] = ax.annotate('', xy=(0, 0),xycoords='data',fontsize=10,horizontalalignment='right', verticalalignment='bottom')
def animate(i) :
moving_point.set_offsets(np.c_[moving_x[0+i], moving_y[0+i]])
circle.center = (radius[i,0], radius[i,1])
xs1L1=-10.0/2**0.5
ys1L1=10.0/2**0.5
xs2L1=10.0/2**0.5
ys2L1=-10.0/2**0.5
xs1L2=-xs1L1
ys1L2=ys1L1
xs2L2=-xs1L2
ys2L2=ys2L1
cx=radius[i,0]
cy=radius[i,1]
theta=math.radians(angles[i][0])
x1L1=( (xs1L1+radius[i,0] - cx) * math.cos(theta) + (ys1L1+radius[i,1] - cy) * math.sin(theta) ) + cx
x2L1=( (xs2L1+radius[i,0] - cx) * math.cos(theta) + (ys2L1+radius[i,1]- cy) * math.sin(theta) ) + cx
y1L1=( -(xs1L1+radius[i,0] - cx) * math.sin(theta) + (ys1L1+radius[i,1] - cy) * math.cos(theta) ) + cy
y2L1=( -(xs2L1+radius[i,0] - cx) * math.sin(theta) + (ys2L1+radius[i,1] - cy) * math.cos(theta) ) + cy
line1.set_data([x1L1,x2L1],[y1L1,y2L1])
x1L2=( (xs1L2+radius[i,0] - cx) * math.cos(theta) + (ys1L2+radius[i,1] - cy) * math.sin(theta) ) + cx
x2L2=( (xs2L2+radius[i,0] - cx) * math.cos(theta) + (ys2L2+radius[i,1]- cy) * math.sin(theta) ) + cx
y1L2=( -(xs1L2+radius[i,0] - cx) * math.sin(theta) + (ys1L2+radius[i,1] - cy) * math.cos(theta) ) + cy
y2L2=( -(xs2L2+radius[i,0] - cx) * math.sin(theta) + (ys2L2+radius[i,1] - cy) * math.cos(theta) ) + cy
line2.set_data([x1L2,x2L2],[y1L2,y2L2])
# Animate compass tags for each frame
tag_pos = np.array([[0,8.5],[8.5,0],[0,-8.5],[-8.5,0]])
tag_pos = tag_pos # rot_mat(angleText[i])
k=0
for tag,pos in zip(annotate_tags,tag_pos):
annotation[k].set_text(tag)
annotation[k].set_position(xy=pos+radius[i])
k=k+1
ani = animation.FuncAnimation(fig, animate, np.arange(0,3), blit = False)
ani.save('test.gif', writer='imagemagick', fps=5)
plt.show()
I'm trying to implement RGB to HSV conversion from opencv in pure numpy using formula from here:
def rgb2hsv_opencv(img_rgb):
img_hsv = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2HSV)
return img_hsv
def rgb2hsv_np(img_rgb):
assert img_rgb.dtype == np.float32
height, width, c = img_rgb.shape
r, g, b = img_rgb[:,:,0], img_rgb[:,:,1], img_rgb[:,:,2]
t = np.min(img_rgb, axis=-1)
v = np.max(img_rgb, axis=-1)
s = (v - t) / (v + 1e-6)
s[v==0] = 0
# v==r
hr = 60 * (g - b) / (v - t + 1e-6)
# v==g
hg = 120 + 60 * (b - r) / (v - t + 1e-6)
# v==b
hb = 240 + 60 * (r - g) / (v - t + 1e-6)
h = np.zeros((height, width), np.float32)
h = h.flatten()
hr = hr.flatten()
hg = hg.flatten()
hb = hb.flatten()
h[(v==r).flatten()] = hr[(v==r).flatten()]
h[(v==g).flatten()] = hg[(v==g).flatten()]
h[(v==b).flatten()] = hb[(v==b).flatten()]
h[h<0] += 360
h = h.reshape((height, width))
img_hsv = np.stack([h, s, v], axis=-1)
return img_hsv
img_bgr = cv2.imread('00000.png')
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
img_rgb = img_rgb / 255.0
img_rgb = img_rgb.astype(np.float32)
img_hsv1 = rgb2hsv_np(img_rgb)
img_hsv2 = rgb2hsv_opencv(img_rgb)
print('max diff:', np.max(np.fabs(img_hsv1 - img_hsv2)))
print('min diff:', np.min(np.fabs(img_hsv1 - img_hsv2)))
print('mean diff:', np.mean(np.fabs(img_hsv1 - img_hsv2)))
But I get big diff:
max diff: 240.0
min diff: 0.0
mean diff: 0.18085355
Do I missing something?
Also maybe it's possible to write numpy code more efficient, for example without flatten?
Also I have hard time finding original C++ code for cvtColor function, as I understand it should be actually function cvCvtColor from C code, but I can't find actual source code with formula.
From the fact that the max difference is exactly 240, I'm pretty sure that what's happening is in the case when both or either of v==r, v==g are simultaneously true alongside v==b, which gets executed last.
If you change the order from:
h[(v==r).flatten()] = hr[(v==r).flatten()]
h[(v==g).flatten()] = hg[(v==g).flatten()]
h[(v==b).flatten()] = hb[(v==b).flatten()]
To:
h[(v==r).flatten()] = hr[(v==r).flatten()]
h[(v==b).flatten()] = hb[(v==b).flatten()]
h[(v==g).flatten()] = hg[(v==g).flatten()]
The max difference may start showing up as 120, because of that added 120 in that equation. So ideally, you would want to execute these three lines in the order b->g->r. The difference should be negligible then (still noticing a max difference of 0.01~, chalking it up to some round off somewhere).
h[(v==b).flatten()] = hb[(v==b).flatten()]
h[(v==g).flatten()] = hg[(v==g).flatten()]
h[(v==r).flatten()] = hr[(v==r).flatten()]
I'm trying to convert (shift) the values of every pixel in an HSV image (taken from a frame of a video).
The idea is to invert yellow and red colours into blue colour (to avoid using three threshold later in the program, when I can use just one) by inverting the red and yellow values into blue values using following equation.
(Hue + 90) % 180 (in OpenCV 3 Hue is in range [0,180])
Here's what I came up with:
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV);
H = hsv[:,:,0]
mask= [H<75 and H>128]
print("orig",hsv[mask])
hsv[mask] = ((hsv[mask]+90) % 180)
Unfortunately It doesn't work as by this approach Im selecting the whole hue channel not its pixel values
There's two different possibilities here, and I'm not sure which you want, but they're both trivial to implement. You can invert (reverse may be a better word) the hue rainbow, which you can just do by using 180 - hue. Or you can shift the color by 180 degrees by using (hue + 90) % 180 like you mention.
Reversing the colors:
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)
rev_h = 180 - h
rev_hsv = cv2.merge([rev_h, s, v])
rev_img = cv2.cvtColor(rev_hsv, cv2.COLOR_HSV2BGR)
Shifting the colors:
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)
shift_h = (h + 90) % 180
shift_hsv = cv2.merge([shift_h, s, v])
shift_img = cv2.cvtColor(shift_hsv, cv2.COLOR_HSV2BGR)
Those are the idiomatic ways to do it in OpenCV.
Now you want to do the same thing as above but only for some masked subset of pixels that meet a condition. This is not too hard to do; if you want to shift some masked pixels:
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)
h_mask = (h < 75) | (h > 128)
h[h_mask] = (h[h_mask] + 90) % 180
shift_hsv = cv2.merge([h, s, v])
shift_img = cv2.cvtColor(shift_hsv, cv2.COLOR_HSV2BGR)
Hue channel is uint8 type, value range is [0, 179]. Therefore, when add with a large number or a negative number, Python returns a garbage number. Here is my solution base on #alkasm color shifting code:
img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(img_hsv)
shift_h = random.randint(-50, 50)
h = ((h.astype('int16') + shift_h) % 180).astype('uint8')
shift_hsv = cv2.merge([h, s, v])
For random hue, saturation, and value shifting. Shift channel base on #bill-grates:
def shift_channel(c, amount):
if amount > 0:
lim = 255 - amount
c[c >= lim] = 255
c[c < lim] += amount
elif amount < 0:
amount = -amount
lim = amount
c[c <= lim] = 0
c[c > lim] -= amount
return c
rand_h, rand_s, rand_v = 50, 50, 50
img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(img_hsv)
# Random shift hue
shift_h = random.randint(-rand_h, rand_h)
h = ((h.astype('int16') + shift_h) % 180).astype('uint8')
# Random shift saturation
shift_s = random.randint(-rand_s, rand_s)
s = shift_channel(s, shift_s)
# Random shift value
shift_v = random.randint(-rand_v, rand_v)
v = shift_channel(v, shift_v)
shift_hsv = cv2.merge([h, s, v])
print(shift_h, shift_s, shift_v)
img_rgb = cv2.cvtColor(shift_hsv, cv2.COLOR_HSV2RGB)