Hi I was wondering if this was possible at all, since I tried it but my variable was always empty. In my project, I'm tracking a static object and a laser pointer via a PiCamera on my raspberry pi, and I calculate the centroids of their contours as (smallx,smally) and (small2x,small2y) respectively.
I use the difference between their coordinates to see if the pointer should go up, down, left, or right in order to meet the 1st static object. After that, it'll choose a direction betweeen 1 through 4 to move, because my direction controls aren't perfectly on an x-y axis and are slanted.
I left the controls and the contour finding out from here and shortened my total code just so that you wouldn't be met with a giant pile of slop to sort through.
EDIT: I' don't think with my understanding I could provide something runnable without posting a couple hundred lines and my little device, but I'll boil it down and post the exact portion of my code where this is relevant. Running Python 2.7.3, using opencv2.4.10
Code:
#import libraries like picamera and opencv
#set empty variables like:
up = down = left = right = set()
smallx = smally = small2x = small2y = 0
#etc etc
with picamera.PiCamera() as camera:
with picamera.array.PiRGBArray(camera) as rawCapture:
#Calibrate my controls with the camera. updates the up, down, left, and right sets.
with picamera.PiCamera() as camera:
with picamera.array.PiRGBArray(camera) as rawCapture:
# Take pictures, threshold them, find contours, append their arrays to list
if len(cnts)>0: #If any objects were identified
contm = sorted(smalList, key=lambda tup: tup[1])
smallest = cnts[smalList[0][0]] #**Take smallest object(my static object)**
smallM = cv2.moments(smallest)
smallx = int(smallM['m10']/smallM['m00']) #**Calculate xcoord**
smally = int(smallM['m01']/smallM['m00']) #**Calculate ycoord**
cv2.line(frame, (smallx,smally), (smallx,smally), 1, 8,0) #Draws centroid
# print(len(cnts))
if len(cnts)==2: #If only 2 objects were identified
smallester = cnts[smalList[1][0]] #** Take pointer object **
small2 = cv2.moments(smallester)
small2x = int(small2['m10']/small2['m00']) #**Calculate xcoord**
small2y = int(small2['m01']/small2['m00']) #**Calculate ycoord**
x = small2x - smallx
y = small2y - smally
print x #These prints return a value
print y
if x < 0: #Difference = Pointer - Object
s1 = right
if x >0:
s1 = left
if y < 0:
s2 = down
if y >0:
s2 = up
print s1, s2 #set([]),set([])
print up,down,left,right #set([1,2]),set([3,4]),set([1,4]),set([2,3])
selecty = s1&s2 #set([])
#Tell the pointer where to go
Should I even be using sets?
Use s1 = s2 = set() instead of = 0.
As for your second question, there are probably better and more known ways to go around your problem. For example, using bit logic:
right = 1
up = 2
left = 4
down = 8
select = 0
if (small2x - smallx) < 0:
select |= right
if (small2x - smallx) >0:
select |= left
if (small2y - smally) < 0:
select |= down
if (small2y - smally) >0:
select |= up
print(select)
print("You chose %s%s%s%s" %("UP " if select & up else "",
"DOWN " if select & down else "",
"LEFT " if select & left else "",
"RIGHT" if select & right else ""))
#Do things after
Related
I have a 5 x 5 grid. Each grid is an object with an id, a value (initially empty), and a possible move set. The possible move set is that given any location on the grid it can move to any new position that is either -16,-21,-12,-3,3,12,21,16 of the current grid id but the position cannot be less than 1 or above 25 (since the grid is 25 positions) and cannot be already occupied.
The objective is to fill the whole grid with numbers 1-25 with the number being the number of the move that positioned there. But there isn't necessarily only one route per starting position so I would like to find all possible paths for a given starting point on the grid.
I have the grid creation working correctly, as well as selecting from the possible options to the next. My issue is concerning several aspects, the rollback to choose a different path if the chosen path was a dead-end or rolling back several levels of selection if there is repeated failure. Additionally finding all paths after one path has been found.
As seen above, for example, if I start at the center at 13 I can move to 2 then 17, etc. If I get stuck I would then move back to the previous point and try another option. I would try all possible options at that level but if it's a dead-end I would move back to another level. The idea is to find a path that uses ALL 25 cells
Given this below code. I can get to the 17th round out of 25 in the selection but I cannot seem to wrap my head around back tracking further to find a 1 complete path let alone multiple:
grid_size = 25
grid = {}
grid_list = []
#initialise grid details
pos_moves=[-16,-21,-12,-3,3,12,21,16 ]
### give all possible moves for this
x = 1
while x <= grid_size:
moves =[]
for i in pos_moves:
if 0 < (x + i) < 26:
moves.append(x + i)
#print(moves)
grid[x] ={ "id" : x, "moves" : moves}
grid_list.append({"id":x})
x += 1
print(grid)
visited = {}
next_location = int
round_level = 1
def choose_path(current_location):
global round_level
global next_location
options = grid[current_location]['moves']
print("################## Round " + str(round_level) + "##################\n" +
"current grid area: " + str(current_location) + "\n"
"current options: " + str(options) + "\n"
)
next_location = options.pop(0)
if next_location not in visited:
visited[next_location] = options
print("Remaining options: " + str(options) + " chosen option" + str(next_location))
print("visited: " + str(visited))
round_level += 1
return choose_path(next_location)
elif next_location in visited:
if len(options) == 0:
print("Visited: " + ",".join(str(key) for key in visited))
print("stopping here")
else:
next_location = options.pop(0)
return choose_path(next_location)
choose_path(13)
I've trying to implement transition from an amount of space to another which is similar to acceleration and deceleration, except i failed and the only thing that i got from this was this infinite stack of mess, here is a screenshot showing this in action:
you can see a very black circle here, which are in reality something like 100 or 200 circles stacked on top of each other
and i reached this result using this piece of code:
def Place_circles(curve, circle_space, cs, draw=True, screen=None):
curve_acceleration = []
if type(curve) == tuple:
curve_acceleration = curve[1][0]
curve_intensity = curve[1][1]
curve = curve[0]
#print(curve_intensity)
#print(curve_acceleration)
Circle_list = []
idx = [0,0]
for c in reversed(range(0,len(curve))):
for p in reversed(range(0,len(curve[c]))):
user_dist = circle_space[curve_intensity[c]] + curve_acceleration[c] * p
dist = math.sqrt(math.pow(curve[c][p][0] - curve[idx[0]][idx[1]][0],2)+math.pow(curve [c][p][1] - curve[idx[0]][idx[1]][1],2))
if dist > user_dist:
idx = [c,p]
Circle_list.append(circles.circles(round(curve[c][p][0]), round(curve[c][p][1]), cs, draw, screen))
This place circles depending on the intensity (a number between 0 and 2, random) of the current curve, which equal to an amount of space (let's say between 20 and 30 here, 20 being index 0, 30 being index 2 and a number between these 2 being index 1).
This create the stack you see above and isn't what i want, i also came to the conclusion that i cannot use acceleration since the amount of time to move between 2 points depend on the amount of circles i need to click on, knowing that there are multiple circles between each points, but not being able to determine how many lead to me being unable to the the classic acceleration formula.
So I'm running out of options here and ideas on how to transition from an amount of space to another.
any idea?
PS: i scrapped the idea above and switched back to my master branch but the code for this is still available in the branch i created here https://github.com/Mrcubix/Osu-StreamGenerator/tree/acceleration .
So now I'm back with my normal code that don't possess acceleration or deceleration.
TL:DR i can't use acceleration since i don't know the amount of circles that are going to be placed between the 2 points and make the time of travel vary (i need for exemple to click circles at 180 bpm of one circle every 0.333s) so I'm looking for another way to generate gradually changing space.
First, i took my function that was generating the intensity for each curves in [0 ; 2]
Then i scrapped the acceleration formula as it's unusable.
Now i'm using a basic algorithm to determine the maximum amount of circles i can place on a curve.
Now the way my script work is the following:
i first generate a stream (multiple circles that need to be clicked at high bpm)
this way i obtain the length of each curves (or segments) of the polyline.
i generate an intensity for each curve using the following function:
def generate_intensity(Circle_list: list = None, circle_space: int = None, Args: list = None):
curve_intensity = []
if not Args or Args[0] == "NewProfile":
prompt = True
while prompt:
max_duration_intensity = input("Choose the maximum amount of curve the change in intensity will occur for: ")
if max_duration_intensity.isdigit():
max_duration_intensity = int(max_duration_intensity)
prompt = False
prompt = True
while prompt:
intensity_change_odds = input("Choose the odds of occurence for changes in intensity (1-100): ")
if intensity_change_odds.isdigit():
intensity_change_odds = int(intensity_change_odds)
if 0 < intensity_change_odds <= 100:
prompt = False
prompt = True
while prompt:
min_intensity = input("Choose the lowest amount of spacing a circle will have: ")
if min_intensity.isdigit():
min_intensity = float(min_intensity)
if min_intensity < circle_space:
prompt = False
prompt = True
while prompt:
max_intensity = input("Choose the highest amount of spacing a circle will have: ")
if max_intensity.isdigit():
max_intensity = float(max_intensity)
if max_intensity > circle_space:
prompt = False
prompt = True
if Args:
if Args[0] == "NewProfile":
return [max_duration_intensity, intensity_change_odds, min_intensity, max_intensity]
elif Args[0] == "GenMap":
max_duration_intensity = Args[1]
intensity_change_odds = Args[2]
min_intensity = Args[3]
max_intensity = Args[4]
circle_space = ([min_intensity, circle_space, max_intensity] if not Args else [Args[0][3],circle_space,Args[0][4]])
count = 0
for idx, i in enumerate(Circle_list):
if idx == len(Circle_list) - 1:
if random.randint(0,100) < intensity_change_odds:
if random.randint(0,100) > 50:
curve_intensity.append(2)
else:
curve_intensity.append(0)
else:
curve_intensity.append(1)
if random.randint(0,100) < intensity_change_odds:
if random.randint(0,100) > 50:
curve_intensity.append(2)
count += 1
else:
curve_intensity.append(0)
count += 1
else:
if curve_intensity:
if curve_intensity[-1] == 2 and not count+1 > max_duration_intensity:
curve_intensity.append(2)
count += 1
continue
elif curve_intensity[-1] == 0 and not count+1 > max_duration_intensity:
curve_intensity.append(0)
count += 1
continue
elif count+1 > 2:
curve_intensity.append(1)
count = 0
continue
else:
curve_intensity.append(1)
else:
curve_intensity.append(1)
curve_intensity.reverse()
if curve_intensity.count(curve_intensity[0]) == len(curve_intensity):
print("Intensity didn't change")
return circle_space[1]
print("\n")
return [circle_space, curve_intensity]
with this, i obtain 2 list, one with the spacing i specified, and the second one is the list of randomly generated intensity.
from there i call another function taking into argument the polyline, the previously specified spacings and the generated intensity:
def acceleration_algorithm(polyline, circle_space, curve_intensity):
new_circle_spacing = []
for idx in range(len(polyline)): #repeat 4 times
spacing = []
Length = 0
best_spacing = 0
for p_idx in range(len(polyline[idx])-1): #repeat 1000 times / p_idx in [0 ; 1000]
# Create multiple list containing spacing going from circle_space[curve_intensity[idx-1]] to circle_space[curve_intensity[idx]]
spacing.append(np.linspace(circle_space[curve_intensity[idx]],circle_space[curve_intensity[idx+1]], p_idx).tolist())
# Sum distance to find length of curve
Length += abs(math.sqrt((polyline[idx][p_idx+1][0] - polyline[idx][p_idx][0]) ** 2 + (polyline [idx][p_idx+1][1] - polyline[idx][p_idx][1]) ** 2))
for s in range(len(spacing)): # probably has 1000 list in 1 list
length_left = Length # Make sure to reset length for each iteration
for dist in spacing[s]: # substract the specified int in spacing[s]
length_left -= dist
if length_left > 0:
best_spacing = s
else: # Since length < 0, use previous working index (best_spacing), could also jsut do `s-1`
if spacing[best_spacing] == []:
new_circle_spacing.append([circle_space[1]])
continue
new_circle_spacing.append(spacing[best_spacing])
break
return new_circle_spacing
with this, i obtain a list with the space between each circles that are going to be placed,
from there, i can Call Place_circles() again, and obtain the new stream:
def Place_circles(polyline, circle_space, cs, DoDrawCircle=True, surface=None):
Circle_list = []
curve = []
next_circle_space = None
dist = 0
for c in reversed(range(0, len(polyline))):
curve = []
if type(circle_space) == list:
iter_circle_space = iter(circle_space[c])
next_circle_space = next(iter_circle_space, circle_space[c][-1])
for p in reversed(range(len(polyline[c])-1)):
dist += math.sqrt((polyline[c][p+1][0] - polyline[c][p][0]) ** 2 + (polyline [c][p+1][1] - polyline[c][p][1]) ** 2)
if dist > (circle_space if type(circle_space) == int else next_circle_space):
dist = 0
curve.append(circles.circles(round(polyline[c][p][0]), round(polyline[c][p][1]), cs, DoDrawCircle, surface))
if type(circle_space) == list:
next_circle_space = next(iter_circle_space, circle_space[c][-1])
Circle_list.append(curve)
return Circle_list
the result is a stream with varying space between circles (so accelerating or decelerating), the only issue left to be fixed is pygame not updating the screen with the new set of circle after i call Place_circles(), but that's an issue i'm either going to try to fix myself or ask in another post
the final code for this feature can be found on my repo : https://github.com/Mrcubix/Osu-StreamGenerator/tree/Acceleration_v02
I'm making a smart bicycle backlight with Raspberry Pi and a SenseHat on top of it.
I'm measuring the output values of the SenseHat's accelerometer. There are actually three values reported as x, y, z and what I'm trying to know is whether my bicycle has been stationary for let's say 15 seconds or more. So if these values have been staying the same for over 15 seconds I'll turn off the backlight. And then if they start changing and stay like that for over 15 seconds, I want it to engage and start functioning again.
So far I've implemented strobe effect that auto activates when the bicycle is in idle. A steering detection - I show arrow animations to left and right based on the object detection sensor i put near the handlebar. I also implemented a brake detection. Once the accelerometer detects the braking, i show full red light.
If you check the code, you can see it's a bit tricky since the whole thing is in while loop and I need to make this detection as an if condition and then add else below, put rest of my existing if conditions there (such as deacceleration or turning detection)
So how do I make Python measure certain values for 15 seconds without using time.delay and do things based on whether they change or stay the same?
while True:
ser.flushInput()
ser.flushOutput()
x, y, z = sense.get_accelerometer_raw().values()
x = round(x, 2)
y = round(y, 2)
z = round(z, 2)
print("x=%s, y=%s, z=%s" % (x, y, z))
input = ser.read() #serial input i'm getting from arduino, it tells me if my left or right steering sensors are triggerred.
yon = input.decode("utf-8")
int(yon)
if (z > 0.20): #If deacceleration is detected
fren() # brake function is called
else: # if no breaking is detected...
if (yon == "1"): #if left turn sensor triggered
sag_ok() #show left turn animation on led matrix
elif (yon =="2"): # if right turn sensor triggered
sol_ok() #show right turn animation on led matrix
else: #anything else
strobe() #show strobe effect if nothing else is detected
There's a number of smaller things that need to be addressed first:
input = ser.read(). input is actually a builtin and shouldn't be used as a variable name
int(yon) does nothing. You may well convert it to an int but the result is lost because you don't assign the result back to a name
if (z > 0.20) and all your other if checks - the brackets actually do nothing here; you can drop them.
A bigger thing to address: That loop is going full-pelt on the CPU core for absolutely no reason. Thousands of times a second, constantly. You should introduce a time.sleep to reduce the load.
Given that, you can achieve your desired output with a mixture of a Boolean flag and a record of when the accelerometer last gave 0 values.
import time
import datetime as dt
last_zeros = None
countdown_started = False
while True:
ser.flushInput()
ser.flushOutput()
x, y, z = sense.get_accelerometer_raw().values()
x = round(x, 2)
y = round(y, 2)
z = round(z, 2)
print("x=%s, y=%s, z=%s" % (x, y, z))
if x == 0 and y == 0 and z == 0:
if countdown_started:
duration = (dt.datetime.utcnow() - last_zeros_time).total_seconds()
if duration > 15:
# Do something to turn the light off here
continue
else:
countdown_started = True
last_zeros_time = dt.datetime.utcnow()
else:
countdown_started = False
sensor_input = ser.read()
yon = sensor_input.decode("utf-8")
if (z > 0.20):
fren()
else:
if (yon == "1"):
sag_ok()
elif (yon =="2"):
sol_ok()
else:
strobe()
time.sleep(0.5)
The basic idea is to keep track of the last time when motion (or non-motion) was detected. If it was more than 15 seconds ago, then turn off (on) the light.
Something like this:
from time import monotonic
TAIL_LIGHT_DELAY = 15
time_of_last_motion = monotinic()
time_of_last_stop = monotonic()
while True:
now = monotonic()
motion = (abs(x) > 0.2) or (abs(y) > 0.2) or (abs(z) > 0.2)
if motion:
time_of_last_motion = now
if now - time_of_last_stop > TAIL_LIGHT_DELAY:
turn_on_tail_light()
else:
time_of_last_stop = now
if now - time_of_last_motion > TAIL_LIGHT_DELAY:
turn_off_tail_light()
Is there a way to separate two polygon shells in Maya API (OpenMaya)? Just like the cmds.polySeparate function (which i cannot use because it returns the separate nodes in random order, so I cannot know which one to delete and which one to keep in my script. Moreover I'd like rely only on the API and don't mix it with the cmds).
Reading the documentations I thought that
OpenMaya.MFnMesh.extractFaces what was I was looking for, but (differently from what the docs seems to say) it just cuts the selected chunk but leaves it in the same node.
Seems like there is no clean way to do this with the API.
Since I needed to separate the mesh to delete the part I didn't need, I decided to maintain the vertices and the polygons that I wanted to remove from the mesh and create a new mesh without them.
As you can see in this function I just keep the "good" vertices and polygons and then I update the vertices IDs in the poly_connects list.
def regenerate_mesh(source_mesh, vertices_to_delete, poly_to_delete):
points = source_mesh.getPoints(om.MSpace.kWorld)
num_points = len(points)
i = 0
while i < num_points:
p1 = points[i]
for p2 in vertices_to_delete['points']:
if p1.x == p2.x and p1.y == p2.y and p1.z == p2.z:
points.remove(i)
num_points -= 1
break
else:
i += 1
polygon_counts, polygon_connects = source_mesh.getVertices()
i = j = 0
polygon_counts_length = len(polygon_counts)
while i < polygon_counts_length:
k = 0
for poly in poly_to_delete:
if poly == polygon_connects[j:j+polygon_counts[i]]:
for l in range(polygon_counts[i]):
polygon_connects.remove(j)
polygon_counts.remove(i)
polygon_counts_length -= 1
break
else:
while k < polygon_counts[i]:
if polygon_connects[j+k] in vertices_to_delete['indices']:
for l in range(polygon_counts[i]):
polygon_connects.remove(j)
polygon_counts.remove(i)
polygon_counts_length -= 1
break
k += 1
else:
j += k
i += 1
# update indices
for vertex in sorted(vertices_to_delete['indices'], reverse=True):
for index, new_vertex in enumerate(polygon_connects):
if new_vertex > vertex:
polygon_connects[index] -= 1
new_mesh = om.MFnMesh()
new_mesh.create(points, polygon_counts, polygon_connects)
If someone find a cleaner way I will be happy to know and mark it as the solution!
I'm working on a 2-player board game (e.g. connect 4), with parametric board size h, w. I want to check for winning condition using hw-sized bitboards.
In game like chess, where board size is fixed, bitboards are usually represented with some sort of 64-bit integer. When h and w are not constant and maybe very big (let's suppose 30*30) are bitboards a good idea? If so, are the any data types in C/C++ to deal with big bitboards keeping their performances?
Since I'm currently working on python a solution in this language is appreciated too! :)
Thanks in advance
I wrote this code while ago just to play around with the game concept. There is no intelligence behaviour involve. just random moves to demonstrate the game. I guess this is not important for you since you are only looking for a fast check of winning conditions. This implementation is fast since I did my best to avoid for loops and use only built-in python/numpy functions (with some tricks).
import numpy as np
row_size = 6
col_size = 7
symbols = {1:'A', -1:'B', 0:' '}
def was_winning_move(S, P, current_row_idx,current_col_idx):
#****** Column Win ******
current_col = S[:,current_col_idx]
P_idx= np.where(current_col== P)[0]
#if the difference between indexes are one, that means they are consecutive.
#we need at least 4 consecutive index. So 3 Ture value
is_idx_consecutive = sum(np.diff(P_idx)==1)>=3
if is_idx_consecutive:
return True
#****** Column Win ******
current_row = S[current_row_idx,:]
P_idx= np.where(current_row== P)[0]
is_idx_consecutive = sum(np.diff(P_idx)==1)>=3
if is_idx_consecutive:
return True
#****** Diag Win ******
offeset_from_diag = current_col_idx - current_row_idx
current_diag = S.diagonal(offeset_from_diag)
P_idx= np.where(current_diag== P)[0]
is_idx_consecutive = sum(np.diff(P_idx)==1)>=3
if is_idx_consecutive:
return True
#****** off-Diag Win ******
#here 1) reverse rows, 2)find new index, 3)find offest and proceed as diag
reversed_rows = S[::-1,:] #1
new_row_idx = row_size - 1 - current_row_idx #2
offeset_from_diag = current_col_idx - new_row_idx #3
current_off_diag = reversed_rows.diagonal(offeset_from_diag)
P_idx= np.where(current_off_diag== P)[0]
is_idx_consecutive = sum(np.diff(P_idx)==1)>=3
if is_idx_consecutive:
return True
return False
def move_at_random(S,P):
selected_col_idx = np.random.permutation(range(col_size))[0]
#print selected_col_idx
#we should fill in matrix from bottom to top. So find the last filled row in col and fill the upper row
last_filled_row = np.where(S[:,selected_col_idx] != 0)[0]
#it is possible that there is no filled array. like the begining of the game
#in this case we start with last row e.g row : -1
if last_filled_row.size != 0:
current_row_idx = last_filled_row[0] - 1
else:
current_row_idx = -1
#print 'col[{0}], row[{1}]'.format(selected_col,current_row)
S[current_row_idx, selected_col_idx] = P
return (S,current_row_idx,selected_col_idx)
def move_still_possible(S):
return not (S[S==0].size == 0)
def print_game_state(S):
B = np.copy(S).astype(object)
for n in [-1, 0, 1]:
B[B==n] = symbols[n]
print B
def play_game():
#initiate game state
game_state = np.zeros((6,7),dtype=int)
player = 1
mvcntr = 1
no_winner_yet = True
while no_winner_yet and move_still_possible(game_state):
#get player symbol
name = symbols[player]
game_state, current_row, current_col = move_at_random(game_state, player)
#print '******',player,(current_row, current_col)
#print current game state
print_game_state(game_state)
#check if the move was a winning move
if was_winning_move(game_state,player,current_row, current_col):
print 'player %s wins after %d moves' % (name, mvcntr)
no_winner_yet = False
# switch player and increase move counter
player *= -1
mvcntr += 1
if no_winner_yet:
print 'game ended in a draw'
player = 0
return game_state,player,mvcntr
if __name__ == '__main__':
S, P, mvcntr = play_game()
let me know if you have any question
UPDATE: Explanation:
At each move, look at column, row, diagonal and secondary diagonal that goes through the current cell and find consecutive cells with the current symbol. avoid scanning the whole board.
extracting cells in each direction:
column:
current_col = S[:,current_col_idx]
row:
current_row = S[current_row_idx,:]
Diagonal:
Find the offset of the desired diagonal from the
main diagonal:
diag_offset = current_col_idx - current_row_idx
current_diag = S.diagonal(offset)
off-diagonal:
Reverse the rows of matrix:
S_reversed_rows = S[::-1,:]
Find the row index in the new matrix
new_row_idx = row_size - 1 - current_row_idx
current_offdiag = S.diagonal(offset)