Is it possible to place an image inside an image with OpenCv (JavaCv).
For example i have a 1000x1000 image and a 100x100 image. And at position 600x600 i would like to place the smaller image inside the larger image.
lets say the blue box is the 1000x1000 IplImage and the red one is the 100x100 IplImage.
Is it possible to put the red box in the blue box. Preferably computational rather efficient because it has to work in real time.
Thx in advance
This is in Python, but conversion to Java is going to be real easy. Use GetSubRect(), and Copy(). GetSubRect() returns a rectangular subarray of interest (specify top left point of interest, and the width and height). Then just copy over the image using Copy().
import cv
blue = cv.LoadImage("blue.jpg")
red = cv.LoadImage("red.jpg")
sub = cv.GetSubRect(blue, (100, 100, 50, 50))
cv.Copy(red,sub)
cv.ShowImage('blue_red', blue)
cv.WaitKey(0)
Alternatively, as karlphillip suggests you could specify the 'region of interest' using SetImageROI(), and do much the same thing:
cv.SetImageROI(blue,(100,100,50,50))
cv.Copy(red, blue)
cv.ResetImageROI(blue)
Its very important to reset the ROI, ResetImageROI, otherwise you will only display/save the ROI, and not the whole image.
Demo output:
blue: red: combined:
Related
I have to generate a new image such that the missing portion of the black ring is shown
For Example, consider this image
As we can see , a sector of the inner black ring is missing, and my task is to identify
where to fill in. I have to take a plain white image of same dimensions as the input image and predict
(marked by black color) the pixels that i’ll fill in to complete the black outer ring. A
pictorial representation of the output image is as follows:
Please help me out...i'm new to OpenCV so please explain me the steps as detailed as possible.I am working in python, so i insist on a python solution for the above problem
You can find a white object (sector) whose centroid is at the maximum distance from the center of the picture.
import numpy as np
import cv2
img = cv2.imread('JUSS0.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
w,h=gray.shape
thresh=cv2.threshold(gray, 253, 255, cv2.THRESH_BINARY )[1]
output = cv2.connectedComponentsWithStats(thresh, 4, cv2.CV_32S)
num_labels = output[0]
labels = output[1]
centroids = output[3]
polar_centroids_sq=[]
for i in range(num_labels):
polar_centroids_sq.append((centroids[i][0]-w/2)**2+(centroids[i][1]-h/2)**2)
idx=polar_centroids_sq.index(max(polar_centroids_sq))
out=np.uint8(255*(labels==idx))
cv2.imshow('sector', out)
cv2.imwrite('sector.png', out)
This is one of many possible approaches.
make every pixel that is not black into white, so your image is black and white. This means your processing is simpler, uses less memory and has only 1 channel to process instead of 3. You can do this with cvtColor() to get greyscale and then cv2.threshold() to get pure black and white.
repeatedly construct (imaginary) radial lines until, when checking the pixels along the lines, you have 2 black stretches. You now have the inner and outer radius of the inner, incomplete circle. You can get the coordinates of points along a line with scikit-image line function.
draw that circle in full in black with cv2.circle()
subtract that image from your initial black and white image so that only the differences (missing part) shows up in the result.
Of course, if you already know the inner and outer radius of the incomplete black ring, you can completely omit the second step above and do what Yves suggested in the comments.
Or, instead of second step above, run edge detection and HoughCircles to get the radii.
Another approach might be to call cv2.warpPolar() to convert your circular image to a long horizontal one with 2 thick black lines, one of them discontinuous. Then just draw that line across the full width of the image and warp back to a circle.
I'm trying to write a program on linux that does something if the pixels in an area aren't all the same color, for example:
if color not "255, 255, 255":
#do something
this is what i have for one pixel:
import time, pyautogui
time.clock()
image = pyautogui.screenshot()
color = image.getpixel((1006, 553))
print(time.clock())
print(color)
I know how to get the color of a pixel using .getpixel() but that only gets one pixel
Basically, how do i get the color of an area of pixels when i know all the pixels in that area are the same color.
Also, as quick as possible, like 0.5s or under.
I keep recommending it, but the scikit-image library is pretty great, and they have some really solid documentation and examples. I would recommend a combo of that and using numpy arrays directly. It is just a lot faster when working directly with pixels.
You will have to convert the PIL image to a numpy array...but this should work with that:
import pyautogui
import numpy as np
image = pyautogui.screenshot()
np_image = np.array(image)
You can slice the image:
red_slice = np_image[0:50, 0:50,0]
red_mask = red_slice == 200
This would give you the values for red in the upper right 50x50 pixel area. red_mask is an array of True/False values whether each red value in that area is equal to 200. This can be repeated for the other channels as you see fit.
I'm trying to find a way to transform an image by translating one of its vertexes.
I have already found various methods for transforming an image like rotation and scaling, but none of the methods involved skewing like so:
There is shearing, but it's not the same since it can move two or more of the image's vertex while I only want to move one.
What can I use that can perform such an operation?
I took your "cat-thing" and resized it to a nice size, added some perfectly vertical and horizontal white gridlines and added some extra canvas in red at the bottom to give myself room to transform it. That gave me this which is 400 pixels wide and 450 pixels tall:
I then used ImageMagick to do a "Bilinear Forward Transform" in Terminal. Basically you give it 4 pairs of points, the first pair is where the top-left corner is before the transform and then where it must move to. The next pair is where the top-right corner is originally followed by where it ends up. Then the bottom-right. Then the bottom-left. As you can see, 3 of the 4 pairs are unmoved - only the bottom-right corner moves. I also made the virtual pixel black so you can see where pixels were invented by the transform in black:
convert cat.png -matte -virtual-pixel black -interpolate Spline -distort BilinearForward '0,0 0,0 399,0 399,0 399,349 330,430 0,349 0,349' bilinear.png
I also did a "Perspective Transform" using the same transform coordinates:
convert cat.png -matte -virtual-pixel black -distort Perspective '0,0 0,0 399,0 399,0 399,349 330,430 0,349 0,349' perspective.png
Finally, to illustrate the difference, I made a flickering comparison between the 2 images so you can see the difference:
I am indebted to Anthony Thyssen for his excellent work here which I commend to you.
I understand you were looking for a Python solution and would point out that there is a Python binding to ImageMagick called Wand which you may like to use - here.
Note that I only used red and black to illustrate what is going on (atop the Stack Overflow white background) and where aspects of the result come from, you would obviously use white for both!
The perspective transformation is likely what you want, since it preserves straight lines at any angle. (The inverse bilinear only preserves horizontal and vertical straight lines).
Here is how to do it in ImageMagick, Python Wand (based upon ImageMagick) and Python OpenCV.
Input:
ImageMagick
(Note the +distort makes the output the needed size to hold the full result and is not restricted to the size of the input. Also the -virtual-pixel white sets color of the area outside the image pixels to white. The points are ordered clockwise from the top left in pairs as inx,iny outx,outy)
convert cat.png -virtual-pixel white +distort perspective \
"0,0 0,0 359,0 359,0 379,333 306,376 0,333 0,333" \
cat_perspective_im.png
Python Wand
(Note the best_fit=true makes the output the needed size to hold the full result and is not restricted to the size of the input.)
#!/bin/python3.7
from wand.image import Image
from wand.display import display
with Image(filename='cat.png') as img:
img.virtual_pixel = 'white'
img.distort('perspective', (0,0, 0,0, 359,0, 359,0, 379,333, 306,376, 0,333, 0,333), best_fit=True)
img.save(filename='cat_perspective_wand.png')
display(img)
Python OpenCV
#!/bin/python3.7
import cv2
import numpy as np
# Read source image.
img_src = cv2.imread('cat.png')
# Four corners of source image
# Coordinates are in x,y system with x horizontal to the right and y vertical downward
pts_src = np.float32([[0,0], [359,0], [379,333], [0,333]])
# Four corners of destination image.
pts_dst = np.float32([[0, 0], [359,0], [306,376], [0,333]])
# Get perspecive matrix if only 4 points
m = cv2.getPerspectiveTransform(pts_src,pts_dst)
# Warp source image to destination based on matrix
# size argument is width x height
# compute from max output coordinates
img_out = cv2.warpPerspective(img_src, m, (359+1,376+1), cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT, borderValue=(255, 255, 255))
# Save output
cv2.imwrite('cat_perspective_opencv.png', img_out)
# Display result
cv2.imshow("Warped Source Image", img_out)
cv2.waitKey(0)
cv2.destroyAllWindows()
I can successfully convert a rectangular image into a png with transparent rounded corners like this:
However, when I take this transparent cornered image and I want to use it in another image generated with Pillow, I end up with this:
The transparent corners become black. I've been playing around with this for a while but I can't find any way in which the transparent parts of an image don't turn black once I place them on another image with Pillow.
Here is the code I use:
mask = Image.open('Test mask.png').convert('L')
im = Image.open('boat.jpg')
im.resize(mask.size)
output = ImageOps.fit(im, mask.size, centering=(0.5, 0.5))
output.putalpha(mask)
output.save('output.png')
im = Image.open('output.png')
image_bg = Image.new('RGBA', (1292,440), (255,255,255,100))
image_fg = im.resize((710, 400), Image.ANTIALIAS)
image_bg.paste(image_fg, (20, 20))
image_bg.save('output2.jpg')
Is there a solution for this? Thanks.
Per some suggestions I exported the 2nd image as a PNG, but then I ended up with an image with holes in it:
Obviously I want the second image to have a consistent white background without holes.
Here is what I actually want to end up with. The orange is only placed there to highlight the image itself. It's a rectangular image with white background, with a picture placed into it with rounded corners.
If you paste an image with transparent pixels onto another image, the transparent pixels are just copied as well. It looks like you only want to paste the non-transparent pixels. In that case, you need a mask for the paste function.
image_bg.paste(image_fg, (20, 20), mask=image_fg)
Note the third argument here. From the documentation:
If a mask is given, this method updates only the regions indicated by
the mask. You can use either "1", "L" or "RGBA" images (in the latter
case, the alpha band is used as mask). Where the mask is 255, the
given image is copied as is. Where the mask is 0, the current value
is preserved. Intermediate values will mix the two images together,
including their alpha channels if they have them.
What we did here is provide an RGBA image as mask, and use the alpha channel as mask.
Basically, I have two images. One is comprised of white and black pixels, the black pixels making up a word, and the other image that I'm trying to paste the black pixels on top of. I've pasted the code below, however I'm aware that there's an issue with the "if pixels [x,y] == (0, 0, 0):' being a tuple and not an indice, however I'm uncertain of how to get it to look for black pixels with other means.
So essentially I need to find, and remember the positions of, the black pixels so that I can paste them onto the first image. Any help is very much appreciated!
image_one = Image.open (image_one)
image_two = Image.open (image_two)
pixels = list(image_two.getdata())
for y in xrange(image_two.size[1]):
for x in xrange(image_two.size[0]):
if pixels[x,y] == (0, 0, 0):
pixels = black_pixels
black_pixels.append()
image = Image.open (image_one);
image_one.putdata(pixels)
image.save(image_one+ "_X.bmp")
del image_one, image_two;
You're almost there. I am not too familiar with the PIL class, but instead of calling the getdata method, let's use getpixel directly on the image object, and directly set the results into the output image. That eliminates the need to store the set of pixels to overwrite. However, there may be cases beyond what you've listed here where such an approach would be necessary. I created a random image and then set various pixels to black. For this test I used a different condition - if the R channel of the image is greater than 50. You can comment that out and use the other test, which tests for tuple (R,G,B) == (0,0,0) which will work fine.
imagea = PIL.Image.open('temp.png')
imageb = PIL.Image.open('temp.png')
for y in xrange(imagea.size[1]):
for x in xrange(imagea.size[0]):
currentPixel = imagea.getpixel((x,y))
if currentPixel[0] > 50:
#if currentPixel ==(0,0,0):
#this is a black pixel, you can directly modify image 2 now
imageb.putpixel((x,y),(0,0,0))
imageb.save('outputfile.png')
An alternative way to do this is just to multiply the two images together. Any pixel that's black in the binary image will be black in the result (multiply by zero) and any pixel that's white in the binary image will be unchanged from the other image in the result (multiply by one).
PIL can do this,
from PIL import Image, ImageChops
image_one = Image.open("image_one.bmp")
image_two = Image.open("image_two.bmp")
out = ImageChops.multiply(image_one, image_two)
out.save("output.bmp")