Good day,
In each iteration step, I have a p1 that describe the location of each person. p1 is a tuple, such that p1 = (x_point, y_point), p1 describes the location of a person in frame i goes.
Based on this article, https://www.pyimagesearch.com/2015/09/21/opencv-track-object-movement/ between line 95 to 109. I am trying to modify the lines in 95 to 109 to measure the distance difference of a person in terms of movement.
The problem can be reproduced as following code, suppose I am getting p1 as each i iteration goes (Originally p1 is the value supplied by SORT Tracking). Since I am dealing with a video with approximately 29 fps as well as multiple objects. Based on following code (inner for loop j), it might provide a false result as following image?
EDIT: It appears to me that inner loop fails to handle multiple objects detection as sample image provided.
Thank you for your time as well.
from collections import deque
from random import randint
import numpy as np
(direction_x, direction_y) = (0, 0)
direction = ""
points_list = deque(maxlen=32)
def sample_of_p1():
return (randint(0, 100),randint(0, 100))
for i in range(100):
p1 = sample_of_p1()
points_list.appendleft(p1)
for j in range(1, len(points_list)):
if(i >= 10):
direction_x = points_list[-10][0] - points_list[j][0]
direction_y = points_list[-10][1] - points_list[j][1]
if np.abs(direction_x) > 0:
dirx = "Right" if np.sign(direction_x) == 1 else "Left"
if np.abs(direction_y) > 0:
diry = "Top" if np.sign(direction_y) == 1 else "Bottom"
if dirx != "" and diry != "":
direction = "{} {}".format(diry, dirx)
else:
direction = dirx if dirx != "" else diry
else:
continue
the code seems to compute correctly but there are some optimizations you can make.
You can put the condition if i >= 10 outside of the loop for j, it is a little optimization but more elegant.
if i >= 10:
for j in range(1, len(points_list)):
//some code
else:
continue
Also, you don't define dirx and diry before the conditions, so you program may throw an exception if you don't move along one axis. In the article, they are initialized at line 109.
Finally, the condition np.abs(direction_x) > 0 seems a bit loose. Usually, when you want to define a movement, you set a minimum value (20 in the article, line 113) to catch a significant movement, and not just a shiver or a negligible movement.
Hope that helps.
Related
Recently, I've been working on a battleship game for my CS2 class. The focus of this project is to create a board game using arrays, and I decided to create a battleship. I have most of the code, but I cannot figure out how to get ships to get randomly generated on a 10x10 array without the ships being...
A. The wrong length
B. Looping around the array
Below is the function I currently have.
def createShips(board):
shipLen = [5,4,3,3,2]
shipAvalible = 5
directionposibilities = ["vertical", "horizontal"]
j = 0
for i in range(shipAvalible):
boatMade = False
#REGULAR VAR STATMENTS
direction = random.choice(directionposibilities)
col = randint(0,9)
row = randint(0,9)
while boatMade == False:
if direction == "vertical":
buildCount = 0
if col + int(shipLen[i]) <= 11:
colission = False
for i in range(0, int(shipLen[i])):
buildCount += 1
if board[int(row-i)][int(col)-1] == "X":
if colission:
pass
else:
colission = True
if colission:
col = randint(0,9)
row = randint(0,9)
else:
for j in range(buildCount):
board[int(row-j)][int(col)-1] = "X"
boatMade = True
else:
col = randint(0,9)
row = randint(0,9)
if direction == "horizontal":
if col + int(shipLen[i]) <= 10:
colission = False
buildCount = 0
for i in range(0, int(shipLen[i])):
buildCount += 1
if board[int(row)][int(col)+i-1] == "X":
if colission:
pass
else:
colission = True
if colission:
col = randint(0,9)
row = randint(0,9)
else:
for j in range(buildCount):
board[int(row)][int(col)+j-1] = "X"
boatMade = True
else:
col = randint(0,9)
row = randint(0,9)
shipAvalible = shipAvalible - 1
return(board)
board = [["■"] * 10 for x in range(10)]
print(createShips(board))
If you have any idea why this may not work please let me know!
P.S. I am using another function that prints the array nicely, if you would like that for convenience, it is seen below:
def showBoard(board):
print(" A B C D E F G H I J")
print(" ------------------------------")
rownumb = 1
for r in board:
if rownumb == 10:
space = ""
else:
space = " "
print("%d|%s|" % (rownumb, space + "|".join(r)))
rownumb += 1
Edit: #Eumel was a bit faster and said it better here
First of all, you have a inner and outer loop with the variable i, which might not actually interfere but it makes it harder to read the code. Consider renaming one of the variables.
When you create a vertical ship, you check the col rather than the row for index error, and does so against a value of 11 instead of your board size 10.
In the vertical case you build the ship "backwards" from the selected position, even though you checked that your board could fit the ship in the positive direction (And you place it in a column to the left). These negative values makes it such that your ships can wrap around.
In the horizontal case you are indexing a bit strange again where board[int(row)][int(col)+i-1] this gives that when i=0 you place your ship an index further to the left than intended, again causing the ship to wrap when col=0.
Further more, you could remove a few redundant if statements and duplicate lines of code, by moving:
direction = choice(directionposibilities)
col = randint(0, 9)
row = randint(0, 9)
Inside the while loop.
Ok lets go over this:
length check
if col + int(shipLen[i]) <= 9: since arrays start at 0 in python the maximum index for a 10x10 board is 9, therefore you need to chek against 9 instead of 11
loop variables
for k in range(0, int(shipLen[i])): using the same variable name for the outer and inner loop (while working in this specific case) is really bad form
collision check
if board[row+k][col] == "X": you want to build the ships "forwards" so you use row+k, you can also forego int conversions when you only use integers to begin with
collsion check 2
if colission: pass else: colission = True This whole block can be shortened to collision = True break since you dont need to keep checking for multiple collisions
buildcount
for j in range(buildCount): unless you get a collision (then you wouldnt be in this branch) buildCount is always the same as shipLen[i] so it can be completly removed from your code
boat building
board[row+j][col] = "X": same as before we build forwards
honorable mentions
shipAvailable = len(shipLen) you could also remove this part completly and iterate over your ships directly in your out for loop
Instead of radoomising your direction row and col on every break condition you could randomize it once at the start of your while loop
j = 0 unlike C you dont have to define your variables before using them in a loop, this statement does nothing
start = time.time()
import csv
f = open('Speed_Test.csv','r+')
coordReader = csv.reader(f, delimiter = ',')
count = -1
successful_trip = 0
trips = 0
for line in coordReader:
successful_single = 0
count += 1
R = interval*0.30
if count == 0:
continue
if 26 < float(line[0]) < 48.7537144 and 26 < float(line[2]) < 48.7537144 and -124.6521017 < float(line[1]) < -68 and -124.6521017 < float(line[3]) < -68:
y2,x2,y1,x1 = convertCoordinates(float(line[0]),float(line[1]),float(line[2]),float(line[3]))
coords_line,interval = main(y1,x1,y2,x2)
for item in coords_line:
loop_count = 0
r = 0
min_dist = 10000
for i in range(len(df)):
dist = math.sqrt((item[1]-df.iloc[i,0])**2 + (item[0]-df.iloc[i,1])**2)
if dist < R:
loop_count += 1
if dist < min_dist:
min_dist = dist
r = i
if loop_count != 0:
successful_single += 1
df.iloc[r,2] += 1
trips += 1
if successful_single == (len(coords_line)):
successful_trip += 1
end = time.time()
print('Percent Successful:',successful_trip/trips)
print((end - start))
I have this code and explaining it would be extremely time consuming but it doesn't run as fast as I need it to in order to be able to compute as much as I'd like. Is there anything anyone sees off the bat that I could do to speed the process up? Any suggestions would be greatly appreciated.
In essence it reads in 2 lat and long coordinates and changes them to a cartesian coordinate and then goes through every coordinate along the path from on origin coordinate to the destination coordinate in certain interval lengths depending on distance. As it is doing this though there is a data frame (df) with 300+ coordinate locations that it checks against each one of the trips intervals and sees if one is within radius R and then stores the shortest on.
Take advantage of any opportunity to break out of a for loop once the result is known. For example, at the end of the for line loop you check to see if successful_single == len(coords_line). But that will happen any time the statement if loop_count != 0 is False, because at that point successful_single will not get incremented; you know that its value will never reach len(coords_line). So you could break out of the for item loop right there - you already know it's not a "successful_trip." There may be other situations like this.
have you considered pooling and running these calculations in parallel ?
https://docs.python.org/2/library/multiprocessing.html
Your code also suggests the variable R,interval might create a dependency and requires a linear solution
I am trying to write code that is an insertion sort. I am trying to get the code to take 2 values and put them into a new list while sorting it. So far it just puts the values into the list without them being sorted, i'm not quite sure why
pos = 0
pos2 = 1
go = True
while go == True:
for i in range(len(ex)-1):
stack.append(ex[pos])
print(stack)
stack.append(ex[pos2])
print(stack)
if stack[pos] > stack[pos2]:
stack[pos], stack[pos2] = stack[pos2], stack[pos]
print(stack)
pos = pos + 2
pos2 = pos2 + 2
I know it's not efficient, but it is based off code i made for a bubble sort which does
go = True
add = 0
while go == True:
for i in range(len(ex)-1):
if ex[i] > ex[i+1]:
go = True
ex[i], ex[i+1] = ex[i+1], ex[i] #flips the numbers in the list
print(ex)
add = add + 1
if add >= len(ex):
go = False
EDIT
I have changed it drastically, but there is still a problem. It only swaps the values once, even if it needs to be swapped multiple times to be in the right place. Here is the code
pos = 0
while pos < len(ex)-1:
for i in range(len(ex)-1):
stack.append(ex[i])
print(stack)
if stack[i-1] > stack[i]:
stack[i-1], stack[i] = stack[i], stack[i-1]
pos = pos + 1
else:
pos = pos + 1
You have to compare ex[pos] with ex[pos2] then you append the right element first :
if ex[pos] > ex[pos2]:
stack[pos].append(ex[pos2])
else stack[pos].append(ex[pos])
print(stack)
Here is the pseudo code for a classic insertion sort from https://visualgo.net/sorting a great resource for learning sorting algorithms:
mark first element as sorted
for each unsorted element
'extract' the element
for i = lastSortedIndex to 0
if currentSortedElement > extractedElement
move sorted element to the right by 1
else: insert extracted element
And here is how you could implement insertion sort in python:
def insertion_sort(l):
for i in range(1, len(l)):
j = i-1
key = l[i]
while (l[j] > key) and (j >= 0):
l[j+1] = l[j]
j -= 1
l[j+1] = key
return l
Once you understand the basic insertion sort you should be able to understand where you went wrong in your implementation in that you are not properly storing stack[pos] in your implementation.
I have a problem where I have to find the largest square in an n * n grid.
e.g.
. . . . .
. # . # .
. # . . .
. # . # .
. # . . .
where the biggest square would be 3 by 3 in the bottom corner.
I am supposed to return the most steps someone could take before turning right so that they can repeat this infinitely without hitting a wall "#" or going outside the n * n square which is why the output is one less that the width/length of the square.
My code loops through the grid left to right, top to bottom looking for vertices that face down and to the right. Once it finds one it then looks for the biggest possible vertex facing up and to the right and when it finds that checks all four sides to see whether or not they are made up or .. This code works in under 1 second for me on anything around n = 100, however I need it to run at 1 second for n = 500. Any tips on how I can speed this up?
import sys
input = sys.stdin.readline
n = int(input())
maze = [list(input()) for _ in range(n)]
squares = 0
for r in range(n - 1):
for c in range(n - 1):
if maze[r][c] == '.' and maze[r][c + 1] == '.' and maze[r + 1] [c] == '.':
sides = []
for i in range(min(n - r - 1, n - c - 1), -1, -1):
if maze[r + i][c + i] == '.' and maze[r + i][c + i - 1] == '.' and maze[r + i - 1][c + i] == '.':
sides = i
if maze[r][c : c + sides] == ['.'] * sides and maze[r + sides][c : c + sides] == ['.'] * sides:
a = True
for j in range(sides):
if maze[r + j][c] != '.' or maze[r + j][c + sides] != '.':
a = False
if a and sides > squares:
squares = sides
break
if squares == n - 1:
break
print(squares)
I can think of a O(n^3) algorithm as follows:
Precompute 4 arrays: top[][], bottom[][], left[][], right[][], each stores the maximum length of a direction that you can go from (i,j)
For each (i,j) , use it as a square's bottom left corner, for each its diagonal points (i-1, j+1), (i-2, j+2)...etc., test if those points can be used as the square's top right corner. Store the maximum square side in the process
For step 1, all 4 arrays can be precomputed in O(n^2)
For step 2, as we loop through all (i,j), and for each (i,j) we have to see at most all diagonal points which is at most n of them, total we get O(n^3)
The test in step 2 can be done in O(1) using the 4 precomputed arrays, simply check if the 4 corners of the "possible squares" can be joined by checking the corresponding directions (top, bottom, left, right)
Of course, there are many minor things which can be done to speed up, for example:
In step 2, for each (i,j), only check for diagonal points which is in the range [current_maximum_diagonal_found ... max(right[i][j], top[i][j])]
Update current_maximum_diagonal_found along the whole algorithm, so that we hope for some (i,j), we do not need to check whole n diagonal points.
But strictly speaking, it is still O(n^3), but as far as I know it should be able to run in 1 second for n~500
that's an interesting problem. I tried out some things and ended up with this implementation which is O(n^3). I commented the code so that you can follow the idea hopefully. There's still room for speed improvements, but this version already does the job (e.g. with maze size 500x500):
Finished after 0.708 seconds.
Result: 112581 squares found, maximum square (x=13, y=270, size=18).
This is the source code (Python 3):
import random
import pprint
import time
# small sample maze
maze = ['.....',
'...#.',
'.#...',
'.#.#.',
'.#...']
# convert to boolean maze
maze_bin = [[True if cell == '.' else False for cell in line] for line in maze]
# uncomment to generate a random maze
# maze_size = 500
# threshold = 0.2
# maze_bin = [[1 if random.random() >= threshold else 0 for _ in range(maze_size)] for _ in range(maze_size)]
# take start time
t1 = time.time()
# rotate the maze (first column becomes first row, first row becomes first column)
maze_bin_rot = [[maze_bin[i][j] for i in range(len(maze_bin))] for j in range(len(maze_bin[0]))]
# horizontal_lengths is a two-dimensional list that contains the number of possible steps to the right for every cell.
horizontal_lengths = []
for line in maze_bin:
num = 0
line_lengths = []
for i in reversed(line):
line_lengths.append(i*num)
num = i * (num + i)
horizontal_lengths.append(tuple(reversed(line_lengths)))
# vertical_lengths is a two-dimensional list that contains the number of possible steps to the bottom for every cell.
vertical_lengths_rot = []
for line in maze_bin_rot:
num = 0
line_lengths = []
for i in reversed(line):
line_lengths.append(i*num)
num = i * (num + i)
vertical_lengths_rot.append(tuple(reversed(line_lengths)))
# do the rotation again to be back in normal coordinates
vertical_lengths = [[vertical_lengths_rot[i][j] for i in range(len(vertical_lengths_rot))] for j in range(len(vertical_lengths_rot[0]))]
# calculate the maximum size of a square that has it's upper left corner at (x, y).
# this is the minimum of the possible steps to the right and to the bottom.
max_possible_square = []
for y in range(len(maze_bin)):
line = []
for x in range(len(maze_bin[0])):
line.append(min(horizontal_lengths[y][x], vertical_lengths[y][x]))
max_possible_square.append(line)
# search for squares
results = []
max_size_square = (-1, -1, -1)
for y in range(len(max_possible_square)):
for x in range(len(max_possible_square[0])):
# start with maximum possible size and decrease size until a square is found.
for size in reversed(range(1, max_possible_square[y][x]+1)):
# look at the upper right (x+size,y) and bottom left corner (x,y+size).
# if it's possible to make at least size steps to the right from the bottom left corner
# and at least size steps to the bottom from the upper right corner, this is a valid square.
if horizontal_lengths[y+size][x] >= size and vertical_lengths[y][x+size] >= size:
results.append((x, y, size+1))
if size+1 > max_size_square[2]:
max_size_square = (x, y, size+1)
# break after the the largest square with upper left corner (x,y) has been found.
break
t2 = time.time()
# comment this print section if you use larger grids
print('Maze:')
pprint.pprint(maze_bin)
print('\n')
print('Horizontal possible steps:')
pprint.pprint(horizontal_lengths)
print('\n')
print('Vertical possible steps:')
pprint.pprint(vertical_lengths)
print('\n')
print('Maximum possible size of square:')
pprint.pprint(max_possible_square)
print('\n')
print('Results:')
for square in results:
print('Square: x={}, y={}, size={}'.format(*square))
print('\n')
# final results
print('Finished after {:.3f} seconds.'.format(t2-t1))
print('Result: {} squares found, maximum square (x={}, y={}, size={}).'.format(len(results), *max_size_square))
I hope this is what you were looking for. If you have any questions, just leave a comment below ;)
If we do not want to enumerate all results, one optimization that may be worth considering is the following. It's based on the strategy - "do not proceed further with this cell if it can not lead to the optimal solution"
for y in range(possible_y_value):
for x in range(possible_x_value):
# We are ready to process cell identified by (x,y).
# Check if max_possible_square_length at this cell is greater than size of best_result seen so far. If so, proceed further, otherwise skip this cell
if max_possible_square[y][x]+1 > best_result.size:
# proceed further with the inner most for loop
....
Even from within the inner most for loop, we can break out of the loop at the iteration when it falls below the best_result's size seen so far
I am implementing a Python version of the game Othello / Reversi. However, my algorithm seems to be having trouble when searching in the southwest direction.
Here are some important functions to understand how my current code works:
def _new_game_board(self)->[[str]]:
board = []
for row in range(self.rows):
board.append([])
for col in range(self.columns):
board[-1].append(0)
return board
def _is_valid_position(self, turn:list)->bool:
'''return true if the turn is a valid row and column'''
row = int(turn[0]) - 1
column = int(turn[1]) - 1
if row >= 0:
if row < self.rows:
if column >= 0:
if column < self.columns:
return True
else:
return False
def _is_on_board(self, row:int, col:int)->bool:
'''returns true is coordinate is on the board'''
if row >=0:
if row < self.rows:
if col >=0:
if col < self.columns:
return True
def _searchNorthEast(self)->None:
'''Search the board NorthEast'''
print("NorthEast")
row = self.move_row
column = self.move_column
should_be_flipped = list()
row += 1
column -= 1
if self._is_on_board(row, column):
print("column searching NorthEast on board")
if self.board[row][column] == self._opponent:
should_be_flipped.append([row, column])
while True:
row += 1
column -= 1
if self._is_on_board(row, column):
if self.board[row][column] == self._opponent:
should_be_flipped.append([row, column])
continue
elif self.board[row][column] == self.turn:
self._to_be_flipped.extend(should_be_flipped)
break
else:
break
else:
self._to_be_flipped.extend(should_be_flipped)
else:
pass
def _searchSouthWest(self)->None:
'''Search the board SouthWest'''
print("in SouthWest")
row = self.move_row
column = self.move_column
should_be_flipped = list()
row -= 1
column += 1
if self._is_on_board(row, column):
print("column searching SouthWest on board")
if self.board[row][column] == self._opponent:
should_be_flipped.append([row, column])
while True:
row -= 1
column += 1
if self._is_on_board(row, column):
if self.board[row][column] == self._opponent:
should_be_flipped.append([row, column])
continue
elif self.board[row][column] == self.turn:
self._to_be_flipped.extend(should_be_flipped)
break
else:
break
else:
self._to_be_flipped.extend(should_be_flipped)
else:
pass
def _move_is_valid(self, turn:list)->bool:
'''Verify move is valid'''
self._to_be_flipped = list()
self._opponent = self._get_opposite(self.turn)
if self._is_valid_position(turn):
self.move_row = int(turn[0]) - 1
self.move_column = int(turn[1]) - 1
self._searchRight()
self._searchLeft()
self._searchUp()
self._searchDown()
self._searchNorthWest()
self._searchNorthEast
self._searchSouthEast()
self._searchSouthWest()
if len(self._to_be_flipped) > 0:
return True
else:
return False
Now let's say the current board looks like the following:
. . . .
W W W .
. B B .
. B . .
Turn: B
and the player makes a move to row 1 column 4, it says invalid because it does not detect the white piece in row 2 column 3 to be flipped. All my other functions are written the same way. I can get it to work in every other direction except in this case.
Any ideas why it is not detecting the piece in this diagonal direction?
Don't Repeat Yourself. The _search* methods are extremely redundant which makes it difficult to see that the signs in
row -= 1
column += 1
are correct. Since you've given only two directions (NE, SW) and no documentation of the board orientation, I cannot tell if the signs agree with the board layout or even agree with themselves.
The _search* methods are also too long and should be divided into multiple functions, but that's a secondary concern.
I agree with msw about not repeating stuff. It is tempting to go ahead and do what you can once you see it, but generalizing will save you the headaches of debugging.
Here is some pseudocode that should give the general idea. I might not be able to finagle working with your code, but hopefully this shows how to reduce repetitive code. Note it doesn't matter if -1 is up or down. The board class is simply a 2x2 array of (open square/player 1's piece/player 2's piece,) along with whose turn it is to move.
# x_delta and y_delta are -1/0/1 each based on which of the up to 8 adjacent squares you are checking. Player_num is the player number.
def search_valid(x_candidate, y_candidate, x_delta, y_delta, board, player_num):
y_near = y_candidate + y_delta
x_near = x_candidate + x_delta
if x_near < 0 or x_near >= board_width:
return False
if y_near < 0 or y_near >= board_width:
return False # let's make sure we don't go off the board and throw an exception
if board.pieces[x_candidate+x_delta][y_candidate+y_delta] == 0:
return False #empty square
if board.pieces[x_candidate+x_delta][y_candidate+y_delta] == player_num:
return False #same color piece
return True #if you wanted to detect how many flips, you could use a while loop
Now a succinct function can loop this search_valid to see whether a move is legal or not e.g.
def check_valid_move(x_candidate, y_candidate, board, player_num):
for dx in [-1, 0, 1]:
for dy in [-1, 0, 1]:
if not x and not y:
continue # this is not a move. Maybe we don't strictly need this, since board.pieces[x_candidate+x_delta][y_candidate+y_delta] == player_num anyway, but it seems like good form.
if search_valid(x_candidate, y_candidate, dx, dy, board, player_num):
return True
return False
A similar function could actually flip all the opposing pieces, but that's a bit trickier. You'd need a while function inside the for loops. But you would not have to rewrite code for each direction.