"Im2col" has already been implemented, Implement MATLAB's im2col 'sliding' in Python, efficiently for 2-D images in Python. I was wondering whether it is possible to extend this to arbitrary N-D images? Many applications involve high-dimensional data (e.g. convolutions, filtering, max pooling, etc.).
So the purpose of this question was really just to post my solution to this problem publicly. I could not seem to find such a solution on Google, so I decided to take a stab at it myself. Turns out the implementation is actually quite simple to extend from "Approach #2" in the post referenced in my question!
Efficient Implementation of N-D "im2col"
def im2col(im, win, strides = 1):
# Dimensions
ext_shp = tuple(np.subtract(im.shape, win) + 1)
shp = tuple(win) + ext_shp
strd = im.strides*2
win_len = np.prod(win)
try:
len(strides)
except:
strides = [strides]*im.ndim
strides = [min(i, s) for i, s in zip(im.shape, strides)]
# Stack all possible patches as an N-D array using a strided view followed by reshaping
col = np.lib.stride_tricks.as_strided(im, shape = shp, strides = strd).reshape(win_len, -1).reshape(-1, *ext_shp)
# Extract patches with stride and reshape into columns
slcs = tuple([slice(None, None, None)] + [slice(None, None, s) for s in strides])
col = col[slcs].reshape(win_len, -1)
return col
Efficient Implementation of N-D "col2im"
def col2im(col, im_shp, win, strides = 1):
# Dimensions
try:
len(strides)
except:
strides = [strides]*len(im_shp)
strides = [min(i, s) for i, s in zip(im_shp, strides)]
# Reshape columns into image
if col.ndim > 1:
im = col.reshape((-1, ) + tuple(np.subtract(im_shp, win)//np.array(strides) + 1))[0]
else:
im = col.reshape(tuple(np.subtract(im_shp, win)//np.array(strides) + 1))
return im
Verification That It Works
Let's define an arbitrary 3-D input:
x = np.arange(216).reshape(6, 6, 6)
print(x)
[[[ 0 1 2 3 4 5]
[ 6 7 8 9 10 11]
[ 12 13 14 15 16 17]
[ 18 19 20 21 22 23]
[ 24 25 26 27 28 29]
[ 30 31 32 33 34 35]]
[[ 36 37 38 39 40 41]
[ 42 43 44 45 46 47]
[ 48 49 50 51 52 53]
[ 54 55 56 57 58 59]
[ 60 61 62 63 64 65]
[ 66 67 68 69 70 71]]
[[ 72 73 74 75 76 77]
[ 78 79 80 81 82 83]
[ 84 85 86 87 88 89]
[ 90 91 92 93 94 95]
[ 96 97 98 99 100 101]
[102 103 104 105 106 107]]
[[108 109 110 111 112 113]
[114 115 116 117 118 119]
[120 121 122 123 124 125]
[126 127 128 129 130 131]
[132 133 134 135 136 137]
[138 139 140 141 142 143]]
[[144 145 146 147 148 149]
[150 151 152 153 154 155]
[156 157 158 159 160 161]
[162 163 164 165 166 167]
[168 169 170 171 172 173]
[174 175 176 177 178 179]]
[[180 181 182 183 184 185]
[186 187 188 189 190 191]
[192 193 194 195 196 197]
[198 199 200 201 202 203]
[204 205 206 207 208 209]
[210 211 212 213 214 215]]]
Let's extract all the patches with a non-uniform window and equal stride:
y = im2col(x, [1, 3, 2], strides = [1, 3, 2])
print(y.T) # transposed for ease of visualization
[[ 0 1 6 7 12 13]
[ 2 3 8 9 14 15]
[ 4 5 10 11 16 17]
[ 18 19 24 25 30 31]
[ 20 21 26 27 32 33]
[ 22 23 28 29 34 35]
[ 36 37 42 43 48 49]
[ 38 39 44 45 50 51]
[ 40 41 46 47 52 53]
[ 54 55 60 61 66 67]
[ 56 57 62 63 68 69]
[ 58 59 64 65 70 71]
[ 72 73 78 79 84 85]
[ 74 75 80 81 86 87]
[ 76 77 82 83 88 89]
[ 90 91 96 97 102 103]
[ 92 93 98 99 104 105]
[ 94 95 100 101 106 107]
[108 109 114 115 120 121]
[110 111 116 117 122 123]
[112 113 118 119 124 125]
[126 127 132 133 138 139]
[128 129 134 135 140 141]
[130 131 136 137 142 143]
[144 145 150 151 156 157]
[146 147 152 153 158 159]
[148 149 154 155 160 161]
[162 163 168 169 174 175]
[164 165 170 171 176 177]
[166 167 172 173 178 179]
[180 181 186 187 192 193]
[182 183 188 189 194 195]
[184 185 190 191 196 197]
[198 199 204 205 210 211]
[200 201 206 207 212 213]
[202 203 208 209 214 215]]
Let's convert this back to a (downsampled) image:
z = col2im(y, x.shape, [1, 3, 2], strides = [1, 3, 2])
print(z)
[[[ 0 2 4]
[ 18 20 22]]
[[ 36 38 40]
[ 54 56 58]]
[[ 72 74 76]
[ 90 92 94]]
[[108 110 112]
[126 128 130]]
[[144 146 148]
[162 164 166]]
[[180 182 184]
[198 200 202]]]
As you can see, the final output is indeed the downsampled image that we expect (you can easily check this by going value by value). The dimensionality and strides I chose were purely illustrative. There's no reason why the window size has to be the same as your stride or that you can't go higher than 3 dimensions.
Applications
If you want to use this practically, all you have to do is intercept the output of im2col before turning it back into an image. For example, if you want to do pooling, you could take the mean or the maximum across the 0th axis. If you want to do a convolution, you just need to multiply this by your flattened convolutional filter.
There may be more efficient alternatives to this already implemented under the hood of Tensorflow, etc. that are faster than "im2col." This is not meant to be the MOST efficient implementation. And of course, you could possibly optimize my code further by eliminating the intermediate reshaping step in "im2col," but it wasn't immediately obvious to me so I just left it at that. If you have a better solution, let me know. Anyways, hope this helps someone else looking for the same answer!
Related
I have a dataframe A of index and column labelled 0 to F (0-15) in hex.
0 1 2 3 4 5 6 7 8 9 A B C D E F
0 99 124 119 123 242 107 111 197 48 1 103 43 254 215 171 118
1 202 130 201 125 250 89 71 240 173 212 162 175 156 164 114 192
2 183 253 147 38 54 63 247 204 52 165 229 241 113 216 49 21
3 4 199 35 195 24 150 5 154 7 18 128 226 235 39 178 117
4 9 131 44 26 27 110 90 160 82 59 214 179 41 227 47 132
5 83 209 0 237 32 252 177 91 106 203 190 57 74 76 88 207
6 208 239 170 251 67 77 51 133 69 249 2 127 80 60 159 168
7 81 163 64 143 146 157 56 245 188 182 218 33 16 255 243 210
8 205 12 19 236 95 151 68 23 196 167 126 61 100 93 25 115
9 96 129 79 220 34 42 144 136 70 238 184 20 222 94 11 219
A 224 50 58 10 73 6 36 92 194 211 172 98 145 149 228 121
B 231 200 55 109 141 213 78 169 108 86 244 234 101 122 174 8
C 186 120 37 46 28 166 180 198 232 221 116 31 75 189 139 138
D 112 62 181 102 72 3 246 14 97 53 87 185 134 193 29 158
E 225 248 152 17 105 217 142 148 155 30 135 233 206 85 40 223
F 140 161 137 13 191 230 66 104 65 153 45 15 176 84 187 22
I did dataframe A by this
df_sbox=pd.DataFrame(from_a_2d_nparray)
df_sbox.index = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'A', 'B', 'C', 'D', 'E', 'F']
df_sbox.columns = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'A', 'B', 'C', 'D', 'E', 'F']
I want to select A where index == 0 - F and column == 0 -F and assign it to a 2D matrix.
What can i use for selecting A where "index == 0 - F and column == 0 -F" in 1 statement?
You can use hex with pandas.DataFrame.loc:
num1 = 10 #row 'A' in hex
num2 = 3 #column 3
df.loc[hex(num1)[2:].upper(), hex(num2)[2:].upper()]
#10
Explanation
You can use python built-in function hex to get the hex representation of an integer:
hex(12)
#0xc
Since we are not interested in the first two characters, we can omit them slicing the str:
hex(12)[2:] #from index 2 onwards
#c
Since the dataframe uses uppercase for its indices and columns, we can use str.upper to match them:
hex(12)[2:].upper()
#'C'
Additional
You can also get the upper-case hex representation using the Standard Format Specifiers:
"{:X}".format(43)
#2B
I'm learning python and am trying to learn about manipulating images. I want to rescale (downscale) a 2D graysacle image to a 1D vector (array of single row/column). In my test code, when I rescale the image, the output values in the array are in decimal (float) format. But I want to rescale and keep the values in the 1D array as integers. Can someone please help/guide me?
This is my code:
#Testing Image to vector
#Importing required functionality
import skimage.io as io
import numpy as np
from skimage.transform import rescale
#read image
image=io.imread("https://www.usna.edu/Users/cs/wcbrown/courses/F14IC210/lab/l09/cat.jpg")
#print image
print (image)
#rescale to 50%
small_im = rescale(image,0.5)
#print the rescaled image
print(small_im)
#manipulate the array
x=np.array(small_im)
#convert to 1D vector
y=np.concatenate(x)
print (y)
#print each value in the 1D vector in a new line. Just to see how far it would go
for i in y:
print (i, end='\n')
A snippet of the output I get is this(it goes way further due to the loop):
[[ 8 8 9 ... 12 11 11]
[ 8 8 9 ... 12 11 11]
[ 7 7 8 ... 12 11 11]
...
[ 5 5 5 ... 98 97 96]
[ 5 5 5 ... 98 97 97]
[ 5 5 5 ... 99 98 97]]
[[0.02745098 0.02941176 0.02941176 ... 0.04509804 0.04313725 0.04313725]
[0.0254902 0.0254902 0.0254902 ... 0.04509804 0.04313725 0.04313725]
[0.0254902 0.0254902 0.0254902 ... 0.04509804 0.04313725 0.04313725]
...
[0.01960784 0.01960784 0.01960784 ... 0.38039216 0.37843137 0.37647059]
[0.01960784 0.01960784 0.01960784 ... 0.38039216 0.37843137 0.37647059]
[0.01960784 0.01960784 0.01960784 ... 0.38039216 0.38039216 0.37843137]]
[0.02745098 0.02941176 0.02941176 ... 0.38039216 0.38039216 0.37843137]
0.027450980392156862
0.029411764705882575
0.029411764705882575
0.027450980392156862
0.03137254901960784
0.03529411764705882
0.03529411764705882
0.032352941176470695
0.03039215686274498
0.02941176470588213
0.030392156862744994
0.03431372549019597
0.03529411764705882
0.0392156862745098
0.0392156862745098
0.0392156862745098
0.0392156862745098
0.0392156862745098
0.043137254901960784
After trying and googling, I've found the answer. At least, in my context, it is what I was trying to achieve.
Solution code:
#solution to converting to 1D vector
#Importing required functionality
import numpy as np
from PIL import Image
#Opening Image and resizing to 10X10 for easy viewing
image_test = np.array(Image.open('1.png').resize((10,10))) #note: I used a local image
#print image
print (image_test)
#manipulate the array
x=np.array(image_test)
#convert to 1D vector
y=np.concatenate(x)
print (y)
#print each value in the 1D vector in a new line. Just to see how far it would go
for i in y:
print (i, end='\n')
Desired sample output (due to the loop it goes further):
[[ 48 52 72 96 96 99 81 71 68 47]
[ 52 85 133 149 168 175 157 116 70 46]
[ 54 129 170 174 185 179 177 169 92 42]
[ 55 142 165 171 187 175 162 167 97 40]
[112 150 144 134 172 157 128 143 129 113]
[162 166 166 158 166 164 154 163 157 155]
[105 166 185 174 170 165 175 179 140 81]
[ 35 113 199 170 147 145 174 181 83 32]
[ 46 65 179 183 160 153 166 155 71 37]
[ 47 58 169 178 170 159 148 158 74 39]]
[ 48 52 72 96 96 99 81 71 68 47 52 85 133 149 168 175 157 116
70 46 54 129 170 174 185 179 177 169 92 42 55 142 165 171 187 175
162 167 97 40 112 150 144 134 172 157 128 143 129 113 162 166 166 158
166 164 154 163 157 155 105 166 185 174 170 165 175 179 140 81 35 113
199 170 147 145 174 181 83 32 46 65 179 183 160 153 166 155 71 37
47 58 169 178 170 159 148 158 74 39]
48
52
72
96
96
99
81
71
68
47
52
85
133
149
168
175
157
116
70
46
I have a time series with extreme events and I tried to get the width of these extreme events using sliding window approach. I used the code:
def moving_window(s, length, step =1):
streams = it.tee(s, length)
return zip(*[it.islice(stream, i, None, step*length) for stream, i in zip(streams, it.count(step=step))])
x_=list(moving_window(s, 15))
x_=np.asarray(x_) #windows
print(x_)
and I have an ouput for the time series:
[[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14]
[ 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29]
[ 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44]
[ 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59]
[ 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74]
[ 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89]
[ 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104]
[105 106 107 108 109 110 111 112 113 114 115 116 117 118 119]
[120 121 122 123 124 125 126 127 128 129 130 131 132 133 134]
[135 136 137 138 139 140 141 142 143 144 145 146 147 148 149]
[150 151 152 153 154 155 156 157 158 159 160 161 162 163 164]
[165 166 167 168 169 170 171 172 173 174 175 176 177 178 179]
[180 181 182 183 184 185 186 187 188 189 190 191 192 193 194]]
I want to highlight the sliding windows with a colormap. What I want is something like the following image:
I want to know how to use a colormap to do this (There are 20 time series in the image but consider only one.). Can anyone help?
Here is an example using a sine function to demonstrate the concept. axvspan draws vertical spans. The color can be set from a colormap. color=0 would be at the left of the map, color=1 totally at the right. Here 'Reds' is used. Some experimenting with alpha and indices suggests an alpha=0.6 and indices 0.75 and lowering gives some similar colors as in the given example.
import matplotlib.pyplot as plt
import numpy as np
x_min = 0
x_max = 120
x = np.linspace(x_min, x_max, 10000)
y = np.sin(x/3)
fig, ax = plt.subplots(figsize=(12,2))
ax.plot(x, y, color='royalblue')
cmap = plt.cm.Reds # e.g. plt.cm.plasma_r or plt.cm.YlOrRd also seem interesting
current_x = 105
x_step = 16
for i in range(8):
ax.axvspan(current_x - (i + 1) * x_step, current_x - i * x_step,
alpha=0.6, color=cmap(0.75 - i / 20))
ax.set_xlim(x_min, x_max)
plt.tight_layout()
plt.show()
Alternatively, instead of varying the color, one could vary the alpha. In the example with only reds, the following leads to something similar:
for i in range(8):
ax.axvspan(current_x - (i + 1) * x_step, current_x - i * x_step,
alpha=0.5 - i / 20, color='red')
Of course, one could vary both alpha and the color together for more fine-tuning. Some experimenting is needed, to find colors that are sufficiently different and that don't scream too much.
Here an example with cmap = plt.cm.inferno_r and ax.axvspan(..., alpha=0.4, color=cmap(0.8 - i / 10)):
I need to display data from the first column and count the number of appearance of every number:
file Path:
[162 164 168 177 189 190 195 254 255 52]
[152 190 195 74 254 164 249 90 151 52]
[ 47 126 254 152 74 195 164 151 189 52]
[116 120 149 164 152 151 195 189 21 52]
[ 34 195 59 199 252 38 82 189 21 52]
[199 164 151 59 82 38 21 189 227 52]
[ 69 170 38 34 177 153 21 189 52 227]
[ 34 107 177 149 118 21 69 189 52 227]
[ 51 88 75 59 38 107 177 189 52 227]
[109 38 149 112 118 51 177 52 189 227]
[ 89 25 75 59 177 170 107 52 189 227]
[244 107 59 170 88 56 89 52 189 227]
[ 30 183 107 59 170 88 56 52 189 227]
Code:
file="Path"
with open(file) as f:
lines = f.readlines()
result = []
for x in lines:
result.append(x.split(' ')[0])
print(result)
f.close()
The expected results are: 162 152, 47, 116, 34, 199, 69, 34, ...
However, what my code gives me is:
['[162', '[152', '[', '[116', '[', '[199', '[', '[', ...
As you read your input, you need to be a little more careful in processing each line. First, slice off the brackets with x[1:-1] (eliminate the end characters).
Now you can split the line, grab the first field, and convert to an integer:
with open("Path") as f:
result = []
for line in f.readlines():
field1 = line[1:-1].split()[0]
result.append(int(field1))
print(result)
Output:
[162, 152, 47, 116, 34, 199, 69, 34, 51, 109, 89, 244, 30]
You can collapse this to a single statement if you want:
result = [int(line[1:-1].split()[0])
for line in open("Path").readlines()]
To just get the first element of each list:
file="Path"
with open(file) as f:
result = [x[0] for x in f.readlines()]
print(result)
To get counts of those values, use Python's Counter:
from collections import Counter
file="Path"
with open(file) as f:
result = [x[0] for x in f.readlines()]
print(Counter(result))
I am trying to rotate some images for data augmentation to train a network for image segmentation task. After searching a lot, the best candidate for rotating each image and its corresponding mask was to use the scipy.ndimage.rotate function, but the problem with this is that after rotating the mask image numpy array ( which includes only 0 and 255 values for pixel values) the rotated mask has got all the values from 0 to 255 while I expect the mask array to have only 0 and 255 as its pixel values.
Here is the code:
from scipy.ndimage import rotate
import numpy as np
ample = dataset[1]
print(np.unique(sample['image']))
print(np.unique(sample['mask']))
print(sample['image'].shape)
print(sample['mask'].shape)
rot_image = rotate(sample['image'], 60, reshape = False)
rot_mask = rotate(sample['mask'], 60, reshape = False)
print(np.unique(rot_image))
print(np.unique(rot_mask))
print(rot_image.shape)
print(rot_mask.shape)
Here are the results:
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
108 109 110 111 112 113 114 115 118 119 120 121 125 139]
[ 0 255]
(512, 512, 1)
(512, 512, 1)
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
108 109 110 111 112 113 115 117 118 124 125 132 135]
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 17 18 20
24 25 26 28 31 34 35 38 39 41 42 43 45 46 48 49 50 51
52 58 59 62 66 67 68 73 75 76 79 80 82 85 86 88 90 96
98 101 108 109 111 114 116 118 119 123 124 125 127 128 130 138 140 142
146 148 151 156 157 158 161 164 165 166 168 169 176 180 184 185 188 189
194 196 197 198 199 201 203 204 205 207 208 210 211 213 216 217 218 219
220 221 222 225 228 229 230 231 233 234 235 237 239 240 241 242 243 244
245 246 247 248 249 250 251 252 253 254 255]
(512, 512, 1)
(512, 512, 1)
It seems to be a simple problem to rotate image array, but I'm searching for days and I didn't find any solution to this problem. I am really confused how to prevent mask array values( 0 and 255) to take all values from 0 to 255 after rotation. I mean something like this:
x = np.unique(sample['mask'])
rot_mask = rotate(sample['mask'], 30, reshape = False)
x_rot = np.unique(rot_mask)
print(np.unique(x - x_rot))
[ 0]
Since you are using numpy arrays to represent images, why not using numpy functions? This library has all sorts of array manipulations. Try the rot90 function