I've got two numpy arrays: data, and a mask. The mask and the data are not the same size, so I imagine them like a canvas and a stamp. How can I stamp my canvas at different locations?
import numpy as np
import matplotlib.pyplot as plt
# Make a canvas
canvas = np.zeros( 2500 ).reshape( 50, 50 )
# Make a "stamp"
r = 10
xx, yy = np.mgrid[ :r * 2, :r * 2 ]
stamp = ((xx - r) ** 2 + (yy - r) ** 2) < r**2
# Draw on the canvas
canvas[stamp] = 10
# Display the drawing
plt.imshow(canvas)
plt.show()
I get this:
How can I stamp at a different location to get something like this?
First crop out the rectangle (with the same size as stamp) from the canvas.
# Draw on the canvas
canvas[x_offset : x_offset + stamp.shape[0],
y_offset : y_offset + stamp.shape[1]][stamp] = 10
Related
I am trying to generate random images of text and store them as image files in my computer so that I can use them to train a model later. But I don't know how make sure all the characters falls within the image boundaries. When I plot them out in python they always show, but if I looked at the saved image, some times the strings are cut. Also, I want to automate the process instead of plotting each out to check.
Furthermore, setting bbox_inches='tight' changes the image size, while I want to be able to specify the image size.
This is what I have tried so far
import matplotlib.pyplot as plt
import numpy as np
dpi = 100
h, w = 50, 100
plt.figure(figsize=(w / dpi, h / dpi), dpi=dpi)# so I will get w columns and h rows
text = str(np.random.uniform(100000, 1000000))# my string will always only be 6 characters
x = np.random.uniform(0, .3)# random positions
y = np.random.uniform(0, .5)
size = np.random.uniform(16, 23)# random text size
plt.text(x, y, text, fontdict={'size': size})
plt.axis('off')
plt.savefig(text + '.jpg'))
I figured a way to get around this. .get_window_extent() can help locate the edges of the text. Since I just want to generate random images, I can drop the image and generate the next one if the text it out of bounds. For non-random text, I suppose one can also use it to determine which way to shift text if it goes out of bounds.
Here is a sample solution with my random text case:
import matplotlib.pyplot as plt
import numpy as np
dpi = 100
w = 120 # number of columns
h = 50 # number of rows
N = 100 # number of random images to generate
count = 0
while count < N:
fig = plt.figure(frameon=False, dpi=dpi)
fig.set_size_inches(w / dpi, h / dpi)
ax = plt.Axes(fig, [0., 0., 1., 1.])
ax.set_axis_off()
fig.add_axes(ax)
number = str(np.random.randint(100000, 1000000))# random text
x = np.random.uniform(0, .1)# random position
y = np.random.uniform(0, .5)
size = np.random.uniform(w / dpi * 72 / 6, w / dpi * 72 / 3.3)
text = ax.text(x, y, number, fontdict={'size': size})
bbox = text.get_window_extent(fig.canvas.get_renderer())# !!! get the extent of the text
if (bbox.x1 < w) & (bbox.y1 < h):# !!! make sure the extent is within bounds before save
plt.savefig(f'{number}.jpg'), pad_inches=0, dpi=dpi)
count += 1
plt.close()# remember to close else bad for memory(?)
I am trying to animate a sample path of Brownian motion by using FuncAnimation, but the animation keeps reverting back to the origin.
Here is my code.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
# create the time interval and partition
t = 2.5
n = 100
# How many sample paths?
path_amt = 2
# Create a brownian sample path
def bsp(t, n):
dB = np.sqrt(t / n) * np.random.normal(0, 1, size=n)
B = np.zeros(n+1)
B[1:] = np.cumsum(dB)
return(B)
# Simulate "path_amt" sample paths
def sample_paths(i, t ,n):
BSP = np.zeros((i, n+1))
for k in range(i):
BSP[k,:] = bsp(t, n)
return(BSP)
B_paths = sample_paths(path_amt, t, n)
This part is essentially just coming up with two independent Browinan motions. Each Brownian motion is a 1-d array of length n+1. I then store the two brownian motions in a (2, n+1) array titled B_paths, so each row represents a brownian motion. Here is the code for the animation.
# Create the animation function for the sample path
x = []
y = []
t_axis = np.linspace(0, t, n+1)
fig, ax = plt.subplots()
ax.set_xlim(0, 3)
ax.set_ylim(-4, 4)
line, = ax.plot(0, 0)
def anim_func(i):
x.append(t_axis[int(i * n / t)])
y.append(B_paths[0][int(i * n / t)])
line.set_xdata(x)
line.set_ydata(y)
return line,
animation = FuncAnimation(fig, func = anim_func, \
frames = np.linspace(0, t, n+1), interval = 10)
plt.show()
Because the animation is looping. Once frame reaches t=2.5, then it starts over, but inside your anim_func you don't clear x, y.
You can either modify this function:
def anim_func(i):
x.append(t_axis[int(i * n / t)])
y.append(B_paths[0][int(i * n / t)])
line.set_xdata(x)
line.set_ydata(y)
if i == t:
x.clear()
y.clear()
return line,
Or set repeat=False in the FuncAnimation call.
I have thousands of images 1000X2000 px and I want count only white pixels in each small windows of image 100X200 and write count number in vector array
please how can I do that by python openCV?
Sample Image:
Opencv and Numpy are pretty good at this. You can use numpy slicing to target each box and numpy.sum to count the number of white pixels in the slice.
import cv2
import numpy as np
# count white pixels per box
def boxCount(img, bw, bh):
# declare output list
counts = [];
h, w = img.shape[:2];
for y in range(0, h - bh + 1, bh):
line = [];
for x in range(0, w - bw + 1, bw):
# slice out box
box = img[y:y+bh, x:x+bw];
# count
count = np.sum(box == 255);
line.append(count);
counts.append(line);
return counts;
# load image
img = cv2.imread("jump.png");
img = cv2.resize(img, (1000, 2000));
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY);
# define box search params
box_width = 100;
box_height = 200;
# get counts
counts = boxCount(img, box_width, box_height);
for line in counts:
print(line);
I am trying to plot some data with a discrete color bar. I was following the example given (https://gist.github.com/jakevdp/91077b0cae40f8f8244a) but the issue is this example does not work 1-1 with different spacing. For example, the spacing in the example in the link is for only increasing by 1 but my data is increasing by 0.5. You can see the output from the code I have.. Any help with this would be appreciated. I know I am missing something key here but cant figure it out.
import matplotlib.pylab as plt
import numpy as np
def discrete_cmap(N, base_cmap=None):
"""Create an N-bin discrete colormap from the specified input map"""
# Note that if base_cmap is a string or None, you can simply do
# return plt.cm.get_cmap(base_cmap, N)
# The following works for string, None, or a colormap instance:
base = plt.cm.get_cmap(base_cmap)
color_list = base(np.linspace(0, 1, N))
cmap_name = base.name + str(N)
return base.from_list(cmap_name, color_list, N)
num=11
x = np.random.randn(40)
y = np.random.randn(40)
c = np.random.randint(num, size=40)
plt.figure(figsize=(10,7.5))
plt.scatter(x, y, c=c, s=50, cmap=discrete_cmap(num, 'jet'))
plt.colorbar(ticks=np.arange(0,5.5,0.5))
plt.clim(-0.5, num - 0.5)
plt.show()
Not sure what version of matplotlib/pyplot introduced this, but plt.get_cmap now supports an int argument specifying the number of colors you want to get, for discrete colormaps.
This automatically results in the colorbar being discrete.
By the way, pandas has an even better handling of the colorbar.
import numpy as np
from matplotlib import pyplot as plt
plt.style.use('ggplot')
# remove if not using Jupyter/IPython
%matplotlib inline
# choose number of clusters and number of points in each cluster
n_clusters = 5
n_samples = 20
# there are fancier ways to do this
clusters = np.array([k for k in range(n_clusters) for i in range(n_samples)])
# generate the coordinates of the center
# of each cluster by shuffling a range of values
clusters_x = np.arange(n_clusters)
clusters_y = np.arange(n_clusters)
np.random.shuffle(clusters_x)
np.random.shuffle(clusters_y)
# get dicts like cluster -> center coordinate
x_dict = dict(enumerate(clusters_x))
y_dict = dict(enumerate(clusters_y))
# get coordinates of cluster center for each point
x = np.array(list(x_dict[k] for k in clusters)).astype(float)
y = np.array(list(y_dict[k] for k in clusters)).astype(float)
# add noise
x += np.random.normal(scale=0.5, size=n_clusters*n_samples)
y += np.random.normal(scale=0.5, size=n_clusters*n_samples)
### Finally, plot
fig, ax = plt.subplots(figsize=(12,8))
# get discrete colormap
cmap = plt.get_cmap('viridis', n_clusters)
# scatter points
scatter = ax.scatter(x, y, c=clusters, cmap=cmap)
# scatter cluster centers
ax.scatter(clusters_x, clusters_y, c='red')
# add colorbar
cbar = plt.colorbar(scatter)
# set ticks locations (not very elegant, but it works):
# - shift by 0.5
# - scale so that the last value is at the center of the last color
tick_locs = (np.arange(n_clusters) + 0.5)*(n_clusters-1)/n_clusters
cbar.set_ticks(tick_locs)
# set tick labels (as before)
cbar.set_ticklabels(np.arange(n_clusters))
Ok so this is the hack I found for my own question. I am sure there is a better way to do this but this works for what I am doing. Feel free to suggest a better way to do this.
import numpy as np
import matplotlib.pylab as plt
def discrete_cmap(N, base_cmap=None):
"""Create an N-bin discrete colormap from the specified input map"""
# Note that if base_cmap is a string or None, you can simply do
# return plt.cm.get_cmap(base_cmap, N)
# The following works for string, None, or a colormap instance:
base = plt.cm.get_cmap(base_cmap)
color_list = base(np.linspace(0, 1, N))
cmap_name = base.name + str(N)
return base.from_list(cmap_name, color_list, N)
num=11
plt.figure(figsize=(10,7.5))
x = np.random.randn(40)
y = np.random.randn(40)
c = np.random.randint(num, size=40)
plt.scatter(x, y, c=c, s=50, cmap=discrete_cmap(num, 'jet'))
cbar=plt.colorbar(ticks=range(num))
plt.clim(-0.5, num - 0.5)
cbar.ax.set_yticklabels(np.arange(0.0,5.5,0.5))
plt.show()
For some reason I cannot upload the image associated with the code above. I get an error when uploading so not sure how to show the final example. But simply I set the color bar axes for tick labels for a vertical color bar and passed in the labels I want and it produced the correct output.
I have a single-band binary image (consisting of only 0 and 1 pixel values) as shown in the figure below.
I have to convert all the black pixels inside the outer white boundaries into whites.
The black pixels outside the outer white boundaries should remain black.
How would you do it?
The code below yields the following result:
I've commented the code inline to explain what I've done.
from skimage import io, img_as_bool, measure, morphology
from scipy import ndimage
import numpy as np
import matplotlib.pyplot as plt
# Read the image, convert the values to True or False;
# discard all but the red channel (since it's a black and
# white image, they're all the same)
image = img_as_bool(io.imread('borders.png'))[..., 0]
# Compute connected regions in the image; we're going to use this
# to find centroids for our watershed segmentation
labels = measure.label(image)
regions = measure.regionprops(labels)
# Marker locations for the watershed segmentation; we choose these to
# be the centroids of the different connected regions in the image
markers = np.array([r.centroid for r in regions]).astype(np.uint16)
marker_image = np.zeros_like(image, dtype=np.int64)
marker_image[markers[:, 0], markers[:, 1]] = np.arange(len(markers)) + 1
# Compute the distance map, which provides a "landscape" for our watershed
# segmentation
distance_map = ndimage.distance_transform_edt(1 - image)
# Compute the watershed segmentation; it will over-segment the image
filled = morphology.watershed(1 - distance_map, markers=marker_image)
# In the over-segmented image, combine touching regions
filled_connected = measure.label(filled != 1, background=0) + 1
# In this optional step, filter out all regions that are < 25% the size
# of the mean region area found
filled_regions = measure.regionprops(filled_connected)
mean_area = np.mean([r.area for r in filled_regions])
filled_filtered = filled_connected.copy()
for r in filled_regions:
if r.area < 0.25 * mean_area:
coords = np.array(r.coords).astype(int)
filled_filtered[coords[:, 0], coords[:, 1]] = 0
# And display!
f, (ax0, ax1, ax2) = plt.subplots(1, 3)
ax0.imshow(image, cmap='gray')
ax1.imshow(filled_filtered, cmap='spectral')
ax2.imshow(distance_map, cmap='gray')
plt.savefig('/tmp/labeled_filled_regions.png', bbox_inches='tight')