VTK rotation operation Using Python - vtk

I would like to ask a question on VTK operations. I have one VTK file and I want to get many images, each taken from a different angle to create a movie of that image.
I have created the following codes (see below). The problem is that although different coordinates will rotate the image to the angles that I want, the zooming is a bit off. So images on some angles appear to be "zoomed in", but other images with different angles appear to be "zoomed out".
I am not sure how should I set all the images to have the same "zooming" scale. Help will be much appreciated. Thank you.
def rotateSave(data, coordinates, filename):
### Set up things
ren = vtk.vtkRenderer()
renWin = vtk.vtkRenderWindow()
renWin.AddRenderer(ren)
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(renWin)
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputData(data)
actor = vtk.vtkActor()
actor.SetMapper(mapper)
### Translate and Rotate
center_x, center_y, center_z = actor.GetCenter()
ren.AddActor(actor)
w = vtk.vtkTransform()
w.Translate(-center_x, -center_y, -center_z)
w.RotateX(coordinates[0])
w.RotateZ(coordinates[2])
actor.SetUserTransform(w)
### Save
renWin.Render()
w2if = vtk.vtkWindowToImageFilter()
w2if.SetInput(renWin)
w2if.Update()
writer = vtk.vtkPNGWriter()
writer.SetFileName(filename.png)
writer.SetInputData(w2if.GetOutput())
writer.Write()
return

In order to set all the images to have the same "zooming" scale, you could reset the camera in the renderer, something like this:
(...)
### Save
ren.ResetCamera()
renWin.Render()
w2if = vtk.vtkWindowToImageFilter()
(...)
Or if you want you can always change the zooming factor:
ren.GetActiveCamera().Zoom(1.2) #increase zoom
ren.GetActiveCamera().Zoom(0.8) #decrease zoom
Please check the vtkCamera (https://www.vtk.org/doc/nightly/html/classvtkCamera.html) class, it has some examples.

Related

How to detect an object in an image rather than screen with pyautogui?

I am using pyautogui.locateOnScreen() function to locate elements in chrome and get their x,y coordinates and click them. But at some point I need to take a screenshot of a part of the screen and search for the object I want in this screenshot. Then I get coordinates of it. Is it possible to do it with pyautogui?
My example code:
coord_one = pyautogui.locateOnScreen("first_image.png",confidence=0.95)
scshoot = pyautogui.screenshot(region=coord_one)
coord_two = # search second image in scshoot and if it can be detected get coordinates of it.
If it is not possible with pyautogui, can you advice the easiest-smartest way?
Thanks in advance.
I don't believe there is a built-in direct way to do what you need but the python-opencv library does the job.
The following code sample assumes you have an screen capture you just took "capture.png" and you want to find "logo.png" in that capture, which you know is an subsection of "capture.png".
Minimal example
"""Get bounding box of cropped image from original image."""
import cv2 as cv
import numpy as np
img_rgb = cv.imread(r'res/original.png')
# the cropped image, expected to be smaller
target_img = cv.imread(r'res/crop.png')
_, w, h = target_img.shape[::-1]
res = cv.matchTemplate(img_rgb,target_img,cv.TM_CCOEFF_NORMED)
# with the method used, the date in res are top left pixel coords
min_val, max_val, min_loc, max_loc = cv.minMaxLoc(res)
top_left = max_loc
# if we add to it the width and height of the target, then we get the bbox.
bottom_right = (top_left[0] + w, top_left[1] + h)
cv.rectangle(img_rgb,top_left, bottom_right, 255, 2)
cv.imshow('', img_rgb)
MatchTemplate
From the docs, MatchTemplate "simply slides the template image over the input image (as in 2D convolution) and compares the template and patch of input image under the template image." Under the hood, this offers methods such as square difference to compare the images represented as arrays.
See more
For a more in-depth explanation, check the opencv docs as the code is entirely based off their example.

How to run multiple color recognition with a user input?

I have a school project where I have to make a line following car that has to follow a specific color line depending on the user input. The code works fine when I test the car's line following capabilities with just one color and no user input, but when I add multiple colors and the user input, the car no longer wants to follow a line and just drives off into the sunset. I have tried to experiment with the code but no luck. This is the while loop of the code.
try:
while(True):
user = int(input("1 for blue line"))
time.sleep(1)
ret, frame = cap.read()
crop_img = frame[60:120, 0:160]
_, img = cap.read()
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# Tracking blue color
if user == 1:
blue_lower = np.array([99,115,150],np.uint8)
blue_upper = np.array([110,255,255],np.uint8)
blue = cv2.inRange(hsv, blue_lower, blue_upper)
kernal = np.ones((5 ,5), "uint8")
blue=cv2.dilate(blue,kernal)
res=cv2.bitwise_and(img, img, mask = blue)
(contours,hierarchy)=cv2.findContours(blue,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
for pic, contour in enumerate(contours):
area = cv2.contourArea(contour)
if(area>300):
x,y,w,h = cv2.boundingRect(contour)
img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
Controls()
# Tracking black color
else:
black_lower = np.array([0,0,0],np.uint8)
black_upper = np.array([50,50,100],np.uint8)
black = cv2.inRange(hsv, black_lower, black_upper)
kernal = np.ones((5 ,5), "uint8")
black = cv2.dilate(black,kernal)
res2 = cv2.bitwise_and(img, img, mask = black)
(contours,hierarchy)=cv2.findContours(black,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
for pic, contour in enumerate(contours):
area = cv2.contourArea(contour)
if(area>300):
x,y,w,h = cv2.boundingRect(contour)
img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
Controls()
I suspect this is due to the user input, although that depends on how Controls() is implemented. input() is a blocking call, meaning the program stops executing until the user presses enter. So, I think your code does this: when you give an input, an image is processed and the car is put in motion. The purpose is then to process a new image and alter the direction of the car if necessary. However, program execution hangs on the input(), so no new image is processed, and the car keeps driving in a straight line, because Controls() is never called/altered.
The solution is to place the input() outside of the while-loop. Now the car should be able the follow the blue line again. Note that you will now have to restart the script to follow a different color.
Lastly, as #Mark-Setchell comments, you make your life a lot easier when you use functions instead of repeating a bunch of code. In your case, you can make a function with the lower and upper colors as parameters. You can learn about functions here.

How to adaptively split an image into regions and set a different text orientation for each one?

Input-Sample
I am trying to pre-process my images in order to improve the ocr quality. However, I am stuck with a problem.
The Images I am dealing with contain different text orientations within the same image (2 pages, 1st is vertical, the 2nd one is horizontally oriented and they are scanned to the same image.
The text direction is automatically detected for the first part. nevertheless, the rest of the text from the other page is completely missed up.
I was thinking of creating a zonal template to detect the regions of interest but I don't know how.
Or automatically detect the border and split the image adaptively then flip the splitted part to achieve the required result.
I could set splitting based on a fixed pixel height but it is not constant as well.
from tesserocr import PyTessBaseAPI, RIL
import cv2
from PIL import Image
with PyTessBaseAPI() as api:
filePath = r'sample.jpg'
img = Image.open(filePath)
api.SetImage(img)
boxes = api.GetComponentImages(RIL.TEXTLINE, True)
print('Found {} textline image components.'.format(len(boxes)))
for i, (im, box, _, _) in enumerate(boxes):
# im is a PIL image object
# box is a dict with x, y, w and h keys
api.SetRectangle(box['x'], box['y'], box['w'], box['h'])
ocrResult = api.GetUTF8Text()
conf = api.MeanTextConf()
for box in boxes:
box = boxes[0][1]
x = box.get('x')
y = box.get('y')
h = box.get('h')
w = box.get('w')
cimg = cv2.imread(filePath)
crop_img = cimg[y:y+h, x:x+w]
cv2.imshow("cropped", crop_img)
cv2.waitKey(0)
output image
as you can see i can apply an orientation detection but I wount get any meaningful text out of such an image.
Try Tesseract API method GetComponentImages and then DetectOrientationScript on each component image.

How to remove the white border from my heat map using python

I've generated 2000 heat maps using seaboard in python3. The problem is that it makes a white border as well. I only want to save the heat map. I want to remove these white borders because I want to train my model based on these heat maps and I think having these borders might mess-up the result. Will having these borders matter since each heat map would have this border?
The code I wrote to generate these heat maps.
for i in range(len(h1)):
ax = sns.heatmap(h1[i], yticklabels = False,xticklabels = False, cbar = False)
fig = ax.get_figure()
fig.savefig(path.join(outpath,"neutral_{0}.png".format(i)))
Actual heat map
What I want:
If you really have same size heat map pictures, you can try trimming them by one more step.
Use PIL(pillow) module to do this work.
For example:
from PIL import Image
for i in range(len(h1)):
im = Image.open("neutral_{0}.png".format(i))
im = im.crop((left, upper, right, lower)) # You have to adjust parameter here
#im = im.crop((100, 75, 300, 150)) # ↓
# you will get an image which size is (width=200, height=75)
im.save("neutral_crop_{0}.png".format(i))
The coordinates of these parameters (left, upper, right, lower) are measured from the top left corner of your input image.

Find contour of a sock that contains patterns

I am trying to figure out how I can isolate a non-uniform sock on a picture.
For now I am using edge detection principally as you can see in my code :
main :
# We import the image
image = importImage(filename)
# Save the shapes variables
height, width, _ = np.shape(image)
# Get the gray scale image in a foot shape
grayImage, bigContourArea = getFootShapeImage(image, True)
minArea = width * height / 50
# Extract all contours
contours = getAllContours(grayImage)
# Keep only the contours that are not too big nor too small
relevantContours = getRelevantContours(contours, minArea, maxArea)
And getAllContours does the following :
kernel = np.ones((5, 5), np.uint8)
# Apply Canny Edge detection algorithm
# We apply a Gaussian blur first
edges = cv2.GaussianBlur(grayIm, (5, 5), 0)
# Then we apply Edge detection
edges = cv2.Canny(edges, 10, 100)
# And we do a dilatation followed by erosion to fill gaps
edges = cv2.dilate(edges, kernel, iterations=2)
edges = cv2.erode(edges, kernel, iterations=2)
_, contours, _ = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
Here are some pictures resulting from my code :
Original picture with foot on the drawed shape
Only the biggers contours
All contours
So as you can see there are some parts of the socks that are not taken in the sock contour, and I tried to include the whole sock with several techniques but never succeeded.
I tried the following :
Segmentation using Otsu thresholding, Itti's saliency (In order to have a mask of the sock in the image and avoid all the remaining)
Regroup the smaller contours with the big one to create an even bigger one (But then I can't avoid taking others that are outside the socks)
Do you have an idea on how i can proceed ?
Thanks in advance ! I hope it is clear enough, if you need clarifications just ask.
In order to solve this I had to perform some color detection algorithm in order to detect the white sheet of paper that is here for this special purpose. I did so with the following :
# Define a mask for color I want to isolate
mask = cv2.inRange(image, lowerWhiteVals, upperWhiteVals)
# I also applied some morphological operations on the mask to make it cleaner
Here is the mask image obtained doing so before and after operations:
Then I detect the paper on the image by taking the left-most contour on the mask, and use it as a left boundary, I also split the paper contour to get a bottom boundary well representative.
And for the top and right I used the first sock contour I had, assuming this one will always at least have theses 2 boundaries because of how the socks are.
Once this was done I just took all the contours in my boundaries and created a new contour from that by drawing them all onto a blank image and finding the new contour again (Thanks to #Alexander Reynolds).
I also had to fine tune a bit my algorithm in order to have the more representative contour of the sock at the end and you can see what my final result is on this following image, even if it's not perfect it's more than enough for this small trial with opencv.
Thanks #Alexander for your help. And hope it will help others someday !

Resources