I managed to create a function that with a given radius, starting point and a number of points. It will create a big circle and withing this circle it will create 4 small circles.
I want to add a grid on the background that will show the Y and X axis in TKinter every 100 pixels apart starting from the top left. The coordinate origin should be the top left corner.
For example if the screen is 300x300 then the window will have 3 lines (at 100, 200 and 300) on his X axis going from left to right and top up to bottom.
A grid as a coordinate system.
Example of how I create a normal line. I use a line class which contains 2 points start point and end point:
rootWindow = Tkinter.Tk()
rootFrame = Tkinter.Frame(rootWindow, width=1000, height=800, bg="white")
rootFrame.pack()
canvas = Tkinter.Canvas(rootFrame, width=1000, height=800, bg="white")
canvas.pack()
def draw_line(l):
"Draw a line with its two end points"
draw_point(l.p1)
draw_point(l.p2)
# now draw the line segment
x1 = l.p1.x
y1 = l.p1.y
x2 = l.p2.x
y2 = l.p2.y
id = canvas.create_line(x1, y1, x2, y2, width=2, fill="blue")
return id
This will create a grid on the canvas for you
import tkinter as tk
def create_grid(event=None):
w = c.winfo_width() # Get current width of canvas
h = c.winfo_height() # Get current height of canvas
c.delete('grid_line') # Will only remove the grid_line
# Creates all vertical lines at intevals of 100
for i in range(0, w, 100):
c.create_line([(i, 0), (i, h)], tag='grid_line')
# Creates all horizontal lines at intevals of 100
for i in range(0, h, 100):
c.create_line([(0, i), (w, i)], tag='grid_line')
root = tk.Tk()
c = tk.Canvas(root, height=1000, width=1000, bg='white')
c.pack(fill=tk.BOTH, expand=True)
c.bind('<Configure>', create_grid)
root.mainloop()
Related
I have two white lines on a black background. I need to input the coordinates of two white pixels and get an answer whether these pixels belong to the same line. Lines are one pixel wide.
Given the constraints of this problem, you can just traverse the path between the two white pixels, summing how many white pixels there are between that path. If they are on the same line, you will sum a lot, otherwise, most of the path will be on the black. Also, you should normalize the sum by the path length, and compare the result to a given threshold.
//x1, y1, x2, y2 and img given as input
double len = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2) + 0.0001;
double dx = (x2-x1)/len; // Division by zero safe
double dy = (y2-y1)/len;
int sum = 0;
for (int i=0; i<len; ++i) {
int x = x1 + (dx*i + 0.5); // 0.5 for rounding when truncating
int y = y1 + (dy*i + 0.5);
sum += img.at<uchar>(y,x) > 200; // White value higher than 200
}
if (sum > len * 0.5) { // 0.5 is the threshold
return 1; // They are on the same line
}
return 0; // Else they are on different lines
Beware of the rounding parameter that I choose as 0.5, it depends on how you are generating that lines.
Here's what I was suggesting in the comments.... starting at either white pixel, floodfill with black. Check colour of other starting pixel. If it's still white, it can't be on the same line we just filled with black.
import cv2
# Load image as greyscale
im = cv2.imread('lines.png', cv2.IMREAD_GRAYSCALE)
w1x, w1y = 171, 108 # bottom line, right end
w2x, w2y = 86, 124 # bottom line. left end
w3x, w3y = 44, 74 # top line, left end
w4x, w4y = 143,25 # top line, right end
# Floodfill with black starting at white px 1
cv2.floodFill(im, None, (w1x,w1y), newVal=0, loDiff=50, upDiff=50, flags=8)
# Check white px 2
print(im[w2y, w2x]) # prints 0 because white px 2 is on same line as white px 1
# Check white px 3
print(im[w3y, w3x]) # prints 255, because white px 3 is on other line
# Check white px 4
print(im[w4y, w4x]) # prints 255, because white px 4 is on other line
Here's the other approach I was suggesting in the comments... join the two points with a white line and see how many objects are now in the image. If there are still 2, we drew along one of the lines. If there is now 1 object, the line we constructed must have joined the other two objects together into a single, larger object:
import cv2
im = cv2.imread('lines.png', cv2.IMREAD_GRAYSCALE)
# Count objects - initially 2
nObjects = len(cv2.findContours(im, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0])
# Draw white line connecting white px 1 and white px 2
cv2.line(im,(w1x,w1y),(w2x,w2y),255,1)
# Count objects - still 2
nObjects = len(cv2.findContours(im, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0])
# Draw white line connecting white px 1 and white px 3
cv2.line(im,(w1x,w1y),(w3x,w3y),255,1)
# Count objects - now just 1
nObjects = len(cv2.findContours(im, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0])
I am very new in the python openCV. I wanted to find the 7 fixed colored randomly curved lines from an image. The result should be boolean which will give me if the image contains the 7 fixed colored randomly curved lines or not. The sample input image is as below:
I also wanted to find out the non-continuous faint green colored trapezium from the image.
I have written the below code to filter out the specific color from the image but unable to detect the lines & unable to conclude if the image is containing the 7 different lines & trapezium. Below is my sample code for the same:
import cv2
import numpy as np
boundaries = [
(32, 230, 32), # 2 Green lines
(10, 230, 230), # 1 Yellow line
(230, 72, 32), # 1 Blue line
(255, 255, 255), # 2 White lines
(32, 72, 230) # 1 Red line
]
box = [(0, 100, 0), (100, 255, 100)]
image = cv2.imread('testImage5.png')
image = removeBlackBands(image)
# cv2.imshow('Cropped Image', image)
# cv2.waitKey(0)
for row in boundaries:
# create NumPy arrays from the boundaries
row = np.array(row, dtype="uint8")
mask = cv2.inRange(image, row, row)
cv2.GaussianBlur(mask, (5,5), 0)
cv2.imshow('Filtered', mask)
cv2.waitKey(0)
lines = cv2.HoughLinesP(mask, cv2.HOUGH_PROBABILISTIC, np.pi / 180, 50, 50, 100)
if lines is not None:
for x in range(0, len(lines)):
print("line ", x)
for x1, y1, x2, y2 in lines[x]:
print("x1 = {}, y1 = {}, x2 = {}, y2 = {}".format(x1, y1, x2, y2))
cv2.line(image,(x1,y1),(x2,y2),(0,0, 255),2, cv2.LINE_AA)
pts = np.array([[x1, y1], [x2, y2]], np.int32)
cv2.polylines(image, [pts], True, (0, 255, 0))
cv2.imshow('Processed.jpg', image)
cv2.waitKey(0)
# create NumPy arrays from the boundaries
lower = np.array(box[0], dtype="uint8")
upper = np.array(box[1], dtype="uint8")
# find the colors within the specified boundaries and apply
# the mask
mask = cv2.inRange(image, lower, upper)
output = cv2.bitwise_and(image, image, mask=mask)
output = cv2.cvtColor(output, cv2.COLOR_BGR2GRAY)
output = cv2.Canny(output, 100, 150)
# show the images
# cv2.imshow("output", output)
# cv2.waitKey(0)
cv2.destroyAllWindows()
Can somebody help me? Thanks in Advance..!!!
This is the function I wrote for the same.
def detectNodes(self, image, tolerance=0):
"""
Detect the nodes in the image
Algorithm used:
1. Pre-process the image to filter out the required color
2. Convert the pre-processed image to binary image
Args:
image(np.ndarray): Numpy Nd array of image
tolerance: (int): Margin of consideration while extracting color from image. Default: 0
Returns
True upon success, False otherwise
"""
noOfNodesDetected = 0
curveWidth = 2
noOfNodeDetectThreshold = 5
cropH = self.testData["nodalROI"].get("height")
cropW = self.testData["nodalROI"].get("width")
roiImage = ppu.crop(image, cropH, cropW) # Crop node ROI
for color in self.nodalColorBoundaries.keys():
filtered = ImageProc.colorFilter(roiImage, colors=self.nodalColorBoundaries[color], tolerance=tolerance)
bgrImage = ppu.convertColorSpace(filtered, "bgr_to_gray")
thresh = ppu.threshold(bgrImage, 1, "thresh_binary")
logging.info("The shape of image is [{}]".format((thresh.shape)))
height, width = thresh.shape
pointFraction = self.testData.get("pointsToFormEquationOfCurve", None)
points = [int(fraction * height) for fraction in pointFraction]
logging.info("Point using for formulating the equation are [{}]".format(points))
pointFractionEvaluation = self.testData.get("pointsForEvaluationOfCurve", None)
pointsForEvaluation_h = [int(fraction * height) for fraction in pointFractionEvaluation]
logging.info("Point using for Evaluating the equation are [{}]".format(pointsForEvaluation_h))
curve1 = []
curve2 = []
for point in points:
prevX = 0
flag = 0
for w in range(0, width):
if thresh[point][w] == 255:
if (abs(prevX - w)) > curveWidth:
if flag == 0:
curve1.append((point, w))
flag = 1
else:
curve2.append((point, w))
prevX = w
fitter = CurveFitter1D()
if curve2:
logging.error("Second curve detected with color {} having points {}".format(color, curve2))
if curve1:
x1 = [point[0] for point in curve1]
y1 = [point[1] for point in curve1]
logging.qvsdebug("Points using to find the Polynomial with color {} are {} ".format(color, curve1))
fitter._fit_polyfit(x1, y1, 4)
logging.qvsdebug("Coefficient of the Polynomial with color {} are {} ".format(
color, fitter._fitterNamespace.coefs))
else:
logging.error("Points not found with {}".format(color))
return False
pointsForEvaluation_w = [int(round(fitter._predY_polyfit(point))) for point in pointsForEvaluation_h]
logging.qvsdebug(
"Points using for the verification of Polynomial representing curve with color {} are {} ".format(
color, zip(pointsForEvaluation_h, pointsForEvaluation_w)))
counter = 0
for i in range(len(pointsForEvaluation_h)):
if pointsForEvaluation_w[i] + 2 >= width:
continue # Continue if control is reaching to width of iamge - 2
if any(thresh[pointsForEvaluation_h[i]][pointsForEvaluation_w[i] - 2:pointsForEvaluation_w[i] + 3]):
counter += 1
logging.info(
"Out of {} points {} points are detected on the curve for color {}".format(len(pointsForEvaluation_h),
counter, color))
nodeDetectThreshold = int(len(pointsForEvaluation_h) * 0.6)
if counter >= nodeDetectThreshold:
noOfNodesDetected += 1
if noOfNodesDetected >= noOfNodeDetectThreshold:
logging.info("Nodes found in this frame are [%d], minimum expected [%d]" % (
noOfNodesDetected, noOfNodeDetectThreshold))
return True
else:
logging.error("Nodes found in this frame are [%d], minimum expected is [%d]" % (
noOfNodesDetected, noOfNodeDetectThreshold))
return False
How do I make a turtle color fade in python 2?
I want to have a square that slowly fades to the middle with a turtle.
from turtle import Turtle
t = Turtle()
t.begin_fill()
t.color('white')
for counter in range(4):
t.forward(100)
t.right(90)
t.color(+1)
t.end_fill()
You can use ontimer() to run periodically function which will redraw rectangle with new color.
import turtle as t
def rect(c):
t.color(c)
t.begin_fill()
for _ in range(4):
t.forward(100)
t.right(90)
t.end_fill()
def fade():
global c
# draw
rect(c)
# change color
r, g, b = c
r += 0.1
g += 0.1
b += 0.1
c = (r, g, b)
# repeat function later
if r <= 1.0 and g <= 1.0 and b <= 1.0:
# run after 100ms
t.ontimer(fade, 100)
# --- main ---
# run fast
t.speed(0)
# starting color
c = (0,0,0) # mode 1.0 color from (0.0,0.0,0.0) to (1.0,1.0,1.0)
# start fadeing
fade()
# start "the engine" so `ontimer` will work
t.mainloop()
I agree with #furas (+1) about using ontimer() but if you're working with a rectanglar shape, I'd go with a simpler implementation, using a turtle to represent your rectangle and changing the turtle's color rather than redrawing anything:
from turtle import Turtle, Screen, mainloop
CURSOR_SIZE = 20
DELAY = 75
DELTA = 0.05
def fade(turtle, gray=0.0):
turtle.color(gray, gray, gray) # easily upgradable to a hue
if gray < 1.0:
screen.ontimer(lambda: fade(turtle, min(gray + DELTA, 1.0)), DELAY)
else:
turtle.hideturtle() # disappear altogether
screen = Screen()
rectangle = Turtle('square')
rectangle.shapesize(90 / CURSOR_SIZE, 100 / CURSOR_SIZE) # "draw" rectangle
fade(rectangle)
mainloop()
beginning CS student here. I am trying to have python 2.7 draw a rectangle using a function that only has the turtle object, the upper left corner coordinates, and the lower right corner coordinates as arguments. I know there are simpler way of drawing a rectangle but I am trying to do it only using corner coordinates.
After running my current code I get the following:
TypeError: can't multiply sequence by non-int of type 'float'
I know this is probably something simple but I am having trouble figuring out what I'm doing wrong so any help would be appreciated.
My code is as follows:
from turtlegraphics import Turtle
def drawLine(t1,x1,y1,x2,y2):
t1.setWidth(1)
t1.setColor(0,0,0)
t1.up()
t1.move(x1,y1)
t1.down()
t1.move(x2,y2)
def rectangleSimple(t2,upperLeftPoint,lowerRightPoint):
t2.setWidth(1)
t2.setColor(0,0,0)
t2.up()
t2.move(upperLeftPoint)
t2.down()
t2.setDirection(270)
t2.move(lowerRightPoint[2])
t2.setDirection(0)
t2.move(lowerRightPoint)
t2.setDirection(90)
t2.move(upperLeftPoint[2])
t2.setDirection(180)
t2.move(upperLeftPoint)
def main():
t1 = Turtle()
x1 = 0
y1 = 0
x2 = 50
y2 = 0
drawLine(t1,x1,y1,x2,y2)
t2 = Turtle()
upperLeftPoint = (-100,50)
lowerRightPoint = (100,-50)
rectangleSimple(t2,upperLeftPoint,lowerRightPoint)
main()
I use the turtle module, not turtlegraphics but my guess is these two lines are at issue:
t2.move(lowerRightPoint[2])
t2.move(upperLeftPoint[2])
Your *Point variables are tuples with two values, X & Y, at indexes 0 & 1 but you're accessing the non-existent third value at index 2. There are many different ways to implement what you're trying to do, here's one using the turtle module that comes with Python:
from turtle import Turtle
X, Y = range(2)
def drawLine(t, x1, y1, x2, y2):
t.up()
t.width(1)
t.pencolor(1, 0, 0) # red
t.goto(x1, y1)
t.down()
t.goto(x2, y2)
def rectangleSimple(t, upperLeftPoint, lowerRightPoint):
t.up()
t.width(1)
t.pencolor(0, 1, 0) # green
t.goto(upperLeftPoint)
t.setheading(0) # East
t.down()
t.goto(lowerRightPoint[X], upperLeftPoint[Y])
t.right(90)
t.goto(lowerRightPoint)
t.right(90)
t.goto(upperLeftPoint[X], lowerRightPoint[Y])
t.right(90)
t.goto(upperLeftPoint)
if __name__ == "__main__":
from turtle import done
t1 = Turtle()
drawLine(t1, 0, 0, 50, 0)
t2 = Turtle()
upperLeftPoint = (-100, 50)
lowerRightPoint = (100, -50)
rectangleSimple(t2, upperLeftPoint, lowerRightPoint)
done()
I am trying to animate arcs and circles. The circles are moving every frame. While the arcs are changing radius, position and disappearing as functions of the positions of the circles.
I am trying to animate these arcs , but they are not changing.
Below is the code sample:
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib import patches
import numpy as np
particle_one = np.zeros((10,2)) #10 times steps and x,y positions
particle_two = np.zeros((10,2)) #10 times steps and x,y positions
#the two particles are moving away from each other in the x direction
for i in range(0,10):
particle_one[i,0] = i
particle_two[i,0] = 2-i
particle_one[i,1] = 2
particle_two[i,1] = -2
particle_One_Radius = 1
particle_Two_Radius = 1.5
arc_Center = np.zeros((10,2))
for i in range(0,10):
arc_Center[i,0] = (particle_one[i,0] + particle_two[i,0])/2
#the arc should disappear for frame 5
arc_Center[5,0] = 0
arc_Center[5,1] = 0
fig = plt.figure()
plt.axis([-20,20, -5,5]) #axis that I like
ax = plt.gca()
circle_One = plt.Circle([particle_one[0,0],particle_one[0,1]],particle_One_Radius)
circle_Two = plt.Circle([particle_two[0,0],particle_two[0,1]],particle_Two_Radius)
circles = []
circles.append(circle_One)
circles.append(circle_Two)
arcs = []
#defines the arc
arc_one = patches.Arc([arc_Center[0,0],arc_Center[0,1]],5,3,angle =0 ,theta1 = 0,theta2= 270)
arcs.append(arc_one)
def init():
ax.add_patch(circles[0])
ax.add_patch(circles[1])
ax.add_patch(arcs[0])
return ax
#draw every frame by frame
def animate(m):
circles[0].center=((particle_one[m,0],particle_one[m,1]))
circles[1].center=((particle_two[m,0],particle_two[m,1]))
#the arcs does not change
arcs[0] =patches.Arc([arc_Center[m,0],arc_Center[m,1]],5+m,3+m,angle =0 ,theta1 = 0,theta2= 270)
return ax
#animation function that draws 10 frames
anim = animation.FuncAnimation(fig,animate , init_func= init , frames = 10 , interval = 20)
plt.show()
The circles animate correctly , but the arc does not change shape or location
Your problem is that instead of modifying your Arc patch as you do the circles, you create a new one at each step, but do not add it to the axes after it's created.
I've checked briefly, but I don't know how to modify the properties of an Arc instance, although I'm sure it's possible.
In the mean time, I've modified your function to remove the previous Arc from the patches list, create a new arc, and add it back to the Axes
#draw every frame by frame
def animate(m):
circles[0].center=((particle_one[m,0],particle_one[m,1]))
circles[1].center=((particle_two[m,0],particle_two[m,1]))
ax.patches.remove(arcs[0])
arcs[0] = patches.Arc([arc_Center[m,0],arc_Center[m,1]],5+m,3+m,angle =0 ,theta1 = 0,theta2= 270)
ax.add_patch(arcs[0])
print "step %d: arc = %s" % (m, arcs[0])
return circles,arcs
I have also ran into the problem of my arc not moving. Trying to remove the arc as Diziet suggested generated the
error: "x not in list".
However, what seems to work is to do both the instantiation of the arc and adding it to the axis within the animate function, but without the call to remove it - essentially, Diziet's solution minus the line "ax.patches.remove(arcs[0])".