How to reconstruct an image that has been divided into several pieces? - python

I'm trying to write a code which gets the pieces of an image, that are represented by an m X m matrix. two pieces belong together if the right side of the matrix of one piece is the same as the left side of the other piece, these two pieces should be "glued".
I wrote the function join which joins two pictures together, I started writing the puzzle solving function but I got stuck and I don't know how to continue.
def join_h(mat1, mat2):
""" joins two matrices, side by side with some separation """
n1,m1 = mat1.dim()
n2,m2 = mat2.dim()
m = m1+m2+10
n = max(n1,n2)
new = Matrix(n, m, val=255) # fill new matrix with white pixels
new[:n1,:m1] = mat1
new[:n2,m1+10:m] = mat2
'''
#without slicing:
for i in range(n1):
for j in range(m1):
new[i,j] = mat1[i,j]
for i in range(n2):
for j in range(m2):
new[i,j+m1+10] = mat2[i,j]
'''
return new
def reconstruct_image(m):
matlst=getlistmatrix()
for i in range(len(matlst)):
if matlst[i][i]==matls[i+1][i+1]
def getlistmatrix():
matrixlst=[]
for i in range(1,1601):
matrixlst.append(Matrix.load('./im'+str(i) +'.bitmap'))
return matrixlst

scikit-learn library provides you with the function 'reconstruct_from_patches_2d' - sklearn.feature_extraction.image.reconstruct_from_patches_2d
If you know the order of the overlapping blocks, then you should be able to use this.
Refer: http://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.image.reconstruct_from_patches_2d.html#sklearn.feature_extraction.image.reconstruct_from_patches_2d
An example provided by them for the same - http://scikit-learn.org/stable/auto_examples/decomposition/plot_image_denoising.html#example-decomposition-plot-image-denoising-py

Related

How to generate complex Hypothesis data frames with internal row and column dependencies?

Is there an elegant way of using hypothesis to directly generate complex pandas data frames with internal row and column dependencies? Let's say I want columns such as:
[longitude][latitude][some-text-meta][some-numeric-meta][numeric-data][some-junk][numeric-data][…
Geographic coordinates can be individually picked at random, but sets must usually come from a general area (e.g. standard reprojections don't work if you have two points on opposite sides of the globe). It's easy to handle that by choosing an area with one strategy and columns of coordinates from inside that area with another. All good so far…
#st.composite
def plaus_spamspam_arrs(
draw,
st_lonlat=plaus_lonlat_arr,
st_values=plaus_val_arr,
st_areas=plaus_area_arr,
st_meta=plaus_meta_arr,
bounds=ARR_LEN,
):
"""Returns plausible spamspamspam arrays"""
size = draw(st.integers(*bounds))
coords = draw(st_lonlat(size=size))
values = draw(st_values(size=size))
areas = draw(st_areas(size=size))
meta = draw(st_meta(size=size))
return PlausibleData(coords, values, areas, meta)
The snippet above makes clean numpy arrays of coordinated single-value data. But the numeric data in the columns example (n-columns interspersed with junk) can also have row-wise dependencies such as needing to be normalised to some factor involving a row-wise sum and/or something else chosen dynamically at runtime.
I can generate all these bits separately, but I can't see how to stitch them into a single data frame without using a clumsy concat-based technique that, I presume, would disrupt draw-based shrinking. Moreover, I need a solution that adapts beyond what's above, so a hack likely get me too far…
Maybe there's something with builds? I just can't quite see out how to do it. Thanks for sharing if you know! A short example as inspiration would likely be enough.
Update
I can generate columns roughly as follows:
#st.composite
def plaus_df_inputs(
draw, *, nrows=None, ncols=None, nrow_bounds=ARR_LEN, ncol_bounds=COL_LEN
):
"""Returns …"""
box_lon, box_lat = draw(plaus_box_geo())
ncols_jnk = draw(st.integers(*ncol_bounds)) if ncols is None else ncols
ncols_val = draw(st.integers(*ncol_bounds)) if ncols is None else ncols
keys_val = draw(plaus_smp_key_elm(size=ncols_val))
nrows = draw(st.integers(*nrow_bounds)) if nrows is None else nrows
cols = (
plaus_df_cols_lonlat(lons=plaus_lon(box_lon), lats=plaus_lat(box_lat))
+ plaus_df_cols_meta()
+ plaus_df_cols_value(keys=keys_val)
+ draw(plaus_df_cols_junk(size=ncols_jnk))
)
random.shuffle(cols)
return draw(st_pd.data_frames(cols, index=plaus_df_idx(size=nrows)))
where the sub-stats are things like
#st.composite
def plaus_df_cols_junk(
draw, *, size=1, names=plaus_meta(), dtypes=plaus_dtype(), unique=False
):
"""Returns strategy for list of columns of plausible junk data."""
result = set()
for _ in range(size):
result.add(draw(names.filter(lambda name: name not in result)))
return [
st_pd.column(name=result.pop(), dtype=draw(dtypes), unique=unique)
for _ in range(size)
]
What I need is something more elegant that incorporates the row-based dependencies.
from hypothesis import strategies as st
#st.composite
def interval_sets(draw):
# To create our interval sets, we'll draw from a strategy that shrinks well,
# and then transform it into the format we want. More specifically, we'll use
# a single lists() strategy so that the shrinker can delete chunks atomically,
# and then rearrange the floats that we draw as part of this.
base_elems = st.tuples(
# Different floats bounds to ensure we get at least one valid start and end.
st.text(),
st.floats(0, 1, exclude_max=True),
st.floats(0, 1, exclude_min=True),
)
base = draw(st.lists(base_elems, min_size=1, unique_by=lambda t: t[0]))
nums = sorted(sum((t[1:] for t in base), start=())) # arrange our endpoints
return [
{"name": name, "start": start, "end": end, "size": end - start}
for (name, _, _), start, end in zip(base, nums[::2], nums[1::2])
]

Find Eucledian distance between landmarks of faces

I've got multiple frames and I've detected the faces in each frame using Retinaface. I would like to keep track of the faces using their landmarks.
To find the similarity between 2 landmarks, I tried to calculate the Eucledian distance :
Input :
landmark_1 = [1828, 911], [1887, 913], [1841, 942], [1832, 974], [1876, 976]
landmark_2 = [1827, 928], [1887, 926], [1848, 963], [1836, 992], [1884, 990]
After referring other links, I wrote the below function, but the values produced are very high :
def euclidean_dist(vector_x, vector_y):
vector_x, vector_y = np.array(vector_x), np.array(vector_y)
if len(vector_x) != len(vector_y):
raise Exception('Vectors must be same dimensions')
ans = sum((vector_x[dim] - vector_y[dim]) ** 2 for dim in range(len(vector_x)))
return np.sqrt(np.sum(ans**2))
Output :
euclidean_dist(landmark_1, landmark_2)
>> 1424.9424549784458
(Expecting some smaller value in this case)
I guess the code can only be used for an one dimensional vector, but I'm really stuck here. Any help would be really appreciated.
It looks like you're squaring the answer twice (ans**2). But you can also simplify the function somewhat:
def euclidean_dist(vector_x, vector_y):
vector_x, vector_y = np.array(vector_x), np.array(vector_y)
return np.sqrt(np.sum((vector_x - vector_y)**2, axis=-1))
This will automatically raise an exception when the vectors are incompatible shapes.
EDIT: If you use axis=-1 it will sum over the last axis of the array, so you can use a 2-D array of vectors, for example.
You can use linalg.nor too.
def euclidean_dist(vector_x, vector_y):
distances = np.linalg.norm(np.array(vector_x)-np.array(vector_y), axis=1)
return distances.tolist()

Nested for loop producing more number of values than expected-Python

Background:I have two catalogues consisting of positions of spatial objects. My aim is to find the similar ones in both catalogues with a maximum difference in angular distance of certain value. One of them is called bss and another one is called super.
Here is the full code I wrote
import numpy as np
def crossmatch(bss_cat, super_cat, max_dist):
matches=[]
no_matches=[]
def find_closest(bss_cat,super_cat):
dist_list=[]
def angular_dist(ra1, dec1, ra2, dec2):
r1 = np.radians(ra1)
d1 = np.radians(dec1)
r2 = np.radians(ra2)
d2 = np.radians(dec2)
a = np.sin(np.abs(d1-d2)/2)**2
b = np.cos(d1)*np.cos(d2)*np.sin(np.abs(r1 - r2)/2)**2
rad = 2*np.arcsin(np.sqrt(a + b))
d = np.degrees(rad)
return d
for i in range(len(bss_cat)): #The problem arises here
for j in range(len(super_cat)):
distance = angular_dist(bss_cat[i][1], bss_cat[i][2], super_cat[j][1], super_cat[j][2]) #While this is supposed to produce single floating point values, it produces numpy.ndarray consisting of three entries
dist_list.append(distance) #This list now contains numpy.ndarrays instead of numpy.float values
for k in range(len(dist_list)):
if dist_list[k] < max_dist:
element = (bss_cat[i], super_cat[j], dist_list[k])
matches.append(element)
else:
element = bss_cat[i]
no_matches.append(element)
return (matches,no_matches)
When put seperately, the function angular_dist(ra1, dec1, ra2, dec2) produces a single numpy.float value as expected. But when used inside the for loop in this crossmatch(bss_cat, super_cat, max_dist) function, it produces numpy.ndarrays instead of numpy.float. I've stated this inside the code also. I don't know where the code goes wrong. Please help

How to iterate over split-up images efficiently with multiprocessing?

I am studying information system engineering and need to suddenly use multi-threading/processing in my side job but we were never taught this at the university so I dont have any idea about it. I only read some introduction over the last couple of days. With that help I even got some simply test programs to perform better, but I wasnt able to do it for this task.
I have a picture with edges of objects as white dots (value 255 in an array).
Now I need to know the position in the array of these dots.
Because images are pretty large arrays and I need to optimize this for a raspberry pi I need to program this with multiprocessing in mind because in a test I only got exactly 25% CPU usage on the pi over 1 core and that was not enough for real time video processing.
def test_multi(self):
pool = mp.Pool(processes=4)
test_prep = self.test_prep.copy()
y, x = test_prep.shape
columns = []
for i in range(4):
c = test_prep[0:y, 0:int(x/4)*(i+1)]
c = copy(c)
columns.append(c)
results = [pool.apply_async(search, args=(c,)) for c in columns]
for r in results:
print(r.get())
def search(picture):
ys, xs = picture.shape
dots = []
for x in range(xs):
for y in range(ys):
if picture[y][x] == 255:
dots.append((x, y))
return dots
But in the result list I can see that it is not really done in parallel because there are 4 entries and each one is just the last one plus some new dots from the next image part. So I think the processes wait for the one before to finish and only than add to the same list but I would like 4 separate lists that I will join afterwards. Also it takes a lot longer than just iterating over the picture the old fashioned way. So what is the problem ?
I tried switching around with multithreading but some people were saying that GIL would not allow the distribution over separate cores.
I tried reading the multiprocessing doc and found a lot of possibilities like queues, managers, pools and pipes but I don't really now what the differences are and when to use what.
I want 4 lists with coordinates of dots in the 4 different columns of the image and I want the search function to be performed in parallel distributed over 4 cores. Or another process that allows a 1920*1080 image to be search faster than in half a second.
UPDATE:
As Mark Setchell suggested I am using cv2.findContour() now but as I said sometimes it detects one contour as multiple ones so I added a routine that combines the middle of the contour that are very similar like this:
def search(image):
ret, thresh = threshold(image, 0, 255, 0)
contours, hierarchy = findContours(thresh, RETR_TREE, CHAIN_APPROX_SIMPLE)
objects = []
for c in contours:
objects.append(middle(c))
any_neighbors = False
while not any_neighbors:
objects, any_neighbors = combine(objects)
return objects
def combine(objects):
ret = objects
any_neighbors = False
for o1 in objects:
for o2 in objects:
if is_neighbor(o1, o2):
ret.remove(o1)
any_neighbors = True
return ret, any_neighbors
def middle(contour):
xs = 0
ys = 0
size = len(contour)
for c in contour:
xs += c[0][0]
ys += c[0][1]
xs = int(xs/size)
ys = int(ys/size)
return xs, ys
def is_neighbor(p1, p2):
return p1[0] - th <= p2[0] <= p1[0] + th and p1[1] - th <= p2[1] <= p1[1] + th
This might still not be perfect but im done for today. I'll be back tomorrow and check if the performance improvement is enough or if I still need to
The process has become as fast as other parts of the program. Thats why multiprocessing wont be necessary anymore.

Flipping Images

I am trying to complete an image editing task in my learning Python book. I need help with the horizontal flip.
The instructions are: Write a function called "flip_horizontal" which will flip the picture horizontally. That is, the pixel that is on the far right end of the row ends up on the far left of the row and vice versa (remember to preserve RGB order!).
My code does not flip the image horizontally when I open it. Also, how can I write my effects to different files (use the original file and apply one function the original file and output it, and then apply another function to the original file and output it to another file). Please, keep in mind that I am only 11 years old and have a very basic understanding of Python and image editing, it is just an interest of mine.
class PPM(object):
def __init__(self, infile, outfile):
self.infile=infile
self.outfile=outfile
#Read in data of image
data= open(self.infile,"r")
datain=data.read()
splits=datain.split()
#Header info
self.type=splits[0]
self.columns=splits[1]
self.row=splits[2]
self.colour=splits[3]
self.pixels=splits[4:]
def negate_red(self):
for b in range (0, (len(self.pixels)) , 3):
remainder=255-self.colour
def writetofile(self):
dataout= open(self.outfile,"w")
dataout.write(self.type +"\n" + self.columns + "\n" + self.row +"\n"+ self.colour +"\n"+ " ".join (self.pixels))
def grey_scale(self):
if int(self.columns) > 1000:
return "ERROR!! Number of columns is larger than what can be held in a buffer."
else:
for b in range(0, (len(self.pixels)) , 3):
sum = int(self.pixels[b]) + int(self.pixels[b+1]) + int(self.pixels[b+2])
avg = int(sum/3)
self.pixels[b] = str(avg)
self.pixels[b+1] = str(avg)
self.pixels[b+2] = str(avg)
def flatten_red(self):
for colour in range (0,len(self.pixels),3):
self.pixels [colour]=str(0)
#Create a 2d lists with the smaller lists containing the rgb values and append lists of lists
def horizontal_flip(self):
if int(self.columns) > 1000:
return "ERROR!! Number of columns is larger than what can be held in a buffer."
else:
temp_list = []
for b in range(int(self.row)):
column_list = []
column_list += self.pixels[0:int(self.columns) * 3]
self.pixels = self.pixels[int(self.columns) * 3 : ]
temp_list.append(column_list)
#print temp_list
new_list = []
for i in range(int(len(temp_list))):
new_list.append (temp_list[i][0])
new_list.append (temp_list[i][1])
new_list.append (temp_list[i][2])
temp_list[i] = temp_list[i][::-1]
sample= PPM("cake.ppm", "Replica.ppm")
sample.flatten_red()
sample.horizontal_flip()
sample.greyscale()
sample.negate_red()
Imagine a row of pixels.
i.imgur.com/1iZesZL.jpg
Now, what we want to do is to flip it so that the right-most pixel is on the left-most place, right?
So if we have the pixel on the far-left with the coordinates (x,y) then the pixel on the far-right has the coordinates (x+n, y) where n = the width of the picture in pixels.
i.imgur.com/EE7Qj5r.jpg
Now, a horizontal flip would look like this, right?
i.imgur.com/fbNLCuX.jpg
So what we do is we go from the far right and the far left, swap the values of the current pixels and go one step to the right and one step to the left until they meet in the middle.
In pseudo-code this might look something like this:
n = width
x = 0
y = whatever row we're on currently
while n != width/2
temporary = (x,y) # (x,y) refers to a specific pixel in the picture
(x,y) = (n, y)
(n, y) = temporary
n = n-1
x = x+1
Do you think that's enough to solve the rest yourself? Wouldn't want to take the fun out of it :-)
Are you really 11 years old?
It looks like each element of your temp_list is a column of the image to reverse the order of the columns you just have to do temp_list = temp_list[::-1], but you're doing temp_list[i] = temp_list[i][::-1] which I think flips the image up-down (I might have it backwards though). Either way, once you get the flip, you'll need to flatten the image again and replace self.pixels, something like:
pixels = []
for column in temp_list:
pixels.extend(column)
self.pixels = pixels
You're not doing much with new_list, I don't think you need it. Also if you want to save the image to different files, take the filename as an argument to writetofile, if you do that you won't need to have it in __init__, so something like:
class PPM(object):
def __init__(self, infile):
self.infile=infile
# More code here
def writetofile(self, outfile):
dataout = open(outfile,"w")
dataout.write(self.type +"\n" + self.columns + "\n" + self.row +"\n"+ self.colour +"\n"+ " ".join (self.pixels))
dataout.close()
sample = PPM("cake.ppm")
sample.horizontal_flip()
sample.writetofile("Replica1.ppm")
sample.negate_red()
sample.writetofile("Replica2.ppm")
Maybe not for you since you want to practice but I came here looking for a solution to the same Problem after Research I found this and wanted to share the following:
OpenCV provides a function to flip an  image.
void flip(array src, array dst, int flipCode)
Flips a 2D array around vertical, horizontal or both axes.
Parameters:
src – The source Array
dst – The destination array; will have the same size and same type as src
flipCode – Specifies how to flip the array: 0 means flipping around the x-axis, positive (e.g., 1) means flipping around y-axis, and negative (e.g., -1) means flipping around both axes.The function flip flips the array in one of three different ways (row and column indices are 0-based).
Example code:
cv.flip(original_image,flip_image,1);

Categories