How to crop image using the Opencv's convexHull coordinates - python-3.x

So I am writing a small program to crop the white part of a license plate (check image). I succeed in finding the white rectangle using an HSV mask (with low and white colours) and by filtering the size of the contours. Nevertheless using:
This is the image i use as a base (i am covering the numbers for privacy reasons)
(x, y, w, h) = cv2.boundingRect(contour)
It gives a rectangle which crops a larger part of the license plate (when the plate is sideways). For this reason I used the following after the filtering:
hull = cv2.convexHull(contour)
cv2.drawContours(copy, contours=[hull],
contourIdx=0,
color=(255, 0, 0), thickness=2)
This marks the correct area on the picture as seen below:
white marked area
Now my main problem is how can I crop only the marked part that was detected using the convexHull functions. I am quite new to the world of computer vision but I could not find something that could help me but from what I understand through my experiments with HSV and HSL I need to create a mask which will crop focus only on the specific area of the image but how can i create a mask from the hull result?
using the boundingRect method i normally do:
# img_plate is the original image
img_plate[y:y + h, x: x + w]
But this will crop a larger image and not the one i really need.
Thank you in advance for all your answers.

Related

Python:Contouring around the rectangle object in a image to obtain the corner points of the rectangle

I have an image which consists of an rectangular object in it and i want to find the 4 corners of the rectangle so that i can calculate the angle of inclination of that object to rotate the image based on that angle.I wanted to know if there are ways to identify the 4 corners of rectangular object so that i can wrap the image using the calculated angle.
I have tried doing some image processing stuff such as converting it gray scale and reducing the noise through Gaussian filter and after which i detect the edge using edge detection filter followed by thresholding and finding the contour.
The problem is that the contours that are found is not consistent and its not performing well on different images from my dataset .Also the background for each of these images is not constant it varies.
Try cv.findContours() on the binarized image, with white object on black background. Then run either cv.boundingRect() or cv.minAreaRect() on the contour.
See Tutorial here: https://docs.opencv.org/3.4/dd/d49/tutorial_py_contour_features.html

Extract rotated rectangle from raster in Python

I'm using GDAL in Python to work with GeoTIFF rasters. I use the following code to extract small rectangular patches from the entire raster:
data_file = gdal.Open("path/to/raster.tiff")
data = data_file.ReadAsArray(xoffset, yoffset, xsize, ysize)
How could I change this code to extract rotated rectangular areas from the raster. For example, I would like to be able to extract data from the area shown in red below.
I'd like the red area to be resampled and rotated, so that I can access it as a simple numpy data array.
I created a solution to this by following this excellent post about how to implement affine transforms.
My solution works by:
Using ReadAsArray to read a section of the full raster that fully contains the red area;
Identifying points p0, p1, p2 representing the top-left, top-right and bottom-left corners of the red area respectively in pixel coordinates;
Implementing the algorithm as described in the link to compute the affine transform, leaving me with the red area on its own, rotated into a horizontal position.

Live camera to shape distance calculation based on computer vision

The goal is to live detect the walls and export the distacne to wall .There is a setup , A closed 4 wall , one set of unique & ideal shape in each wall ( Triangle , Square .....) A robot with camera will roam inside the walls and have computer vision. Robot should detect the shape and export the distance between camera and wall( or that shape ).
I have implemented this goal by Opencv and the shape detection ( cv2.approxPolyDP ) and distance calculation ( perimeter calculation and edge counting then conversion of pixel length to real distance ).
It perfectly works in 90 degree angle , but not effective when happening in other angles.
Any better way of doing it.
Thanks
for cnt in contours[1:]:
# considering countours from 1 because from practical experience whole frame is often considered as a contour
area = cv2.contourArea(cnt)
# area of detected contour
approx = cv2.approxPolyDP(cnt, 0.02*cv2.arcLength(cnt, True), True)
#It predicts and makes pixel connected contour to a shape
x = approx.ravel()[0]
y = approx.ravel()[1]
# detected shape type label text placement
perimeter = cv2.arcLength(cnt,True)
# find perimeter
in other degrees you have the perspective view of the shapes.
you must use Geometric Transformations to neutralize perspective effect (using a known-shape object or angle of the camera).
also consider that using rectified images is highly recommended Camera Calibration.
Edit:
lets assume you have a square on the wall. when camera capture an image from non-90-degree straight-on view of the object. the square is not align and looks out of shape, this causes measurement error.
but you can use cv2.getPerspectiveTransform() .the function calculates the 3x3 matrix of a perspective transform M.
after that use warped = cv2.warpPerspective(img, M, (w,h)) and apply perspective transformation to the image. now the square (in warped image) looks like 90-degree straight-on view and your current code works well on the output image (warped image).
and excuse me for bad explanation. maybe this blog posts can help you:
4 Point OpenCV getPerspective Transform Example
Find distance from camera to object/marker using Python and OpenCV

crop images with different black margins

I have an image dataset and before feeds it to deep learning algorithm I need to crop it to the same size. All images have different size of black margins as the below image demonstrates.
Any suggestions for a way to crop images with different margin size.
Since your border color is black (nearly perfect black) and will be the same in all the images, I would suggest applying binary threshold making everything white (255) except the black region. Now some of the image regions may get affected too but that's not a problem.
Now find contours in the image and second largest contour will be your region. Calculate rectangular bounding box for this contour and crop the same region in the original image.
First, do a thresholding with a low-intensity threshold value (if your background is definitely completely black, you could even threshold at an intensity of 1) to determine all non-border components.
Next, use Connected-component labeling to determine all isolated foreground components. The central scan-image you are interested in should then always result in the biggest component. Crop out this biggest component to remove the border together with all possible non-black artifacts (labels, letters etc.). You should be left with only the borderless scan.
You can find all the algorithms needed in any basic image processing library. I'd personally recommend looking into OpenCV, they also include phyton bindings.
One way to this could be as follows:
Flood-fill the image with red starting at the top-left corner, and allowing around 5% divergence from the black pixel there.
Now make everything that is not red into white - because the next step after this looks for white pixels.
Now use findContours() (which looks for white objects) and choose the largest white contour as your image and crop to that.
You could consider making things more robust by considering some of the following ideas:
You could normalise a copy of the image to the full range of black to white first in case you get any with near-black borders.
You could check that more than one, or all corner pixels are actually black in case you get images without a border.
You could also flag up issues if your cropped image appears to be less than, say 70%, of the total image area.
You could consider a morphological opening with 9x9 square structuring element as the penultimate step to tidy things up before findContrours().
here is the solution code for this question:
import warnings
warnings.filterwarnings('always')
warnings.filterwarnings('ignore')
import cv2
import numpy as np
import os
path = "data/benign/"
img_resized_dir = "data/pre-processed/benign/"
dirs = os.listdir(path)
def thyroid_scale():
for item in dirs:
if os.path.isfile(path+item):
img = cv2.imread(path+item)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray,0,255,0)
im2, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
areas = [cv2.contourArea(c) for c in contours]
max_index = np.argmax(areas)
cnt=contours[max_index]
x,y,w,h = cv2.boundingRect(cnt)
crop_img = img[y+35:y+h-5,x+25:x+w-10]
resize_img = cv2.resize(crop_img, (300, 250), interpolation = cv2.INTER_CUBIC)
cv2.imwrite(img_resized_dir+item, resize_img)
thyroid_scale()

How to group together all strokes of a same kind on an image?

Question preamble
I want to group together all strokes which are below a spatial threshold. I want to do this in order to use entropy to distinguish shape versus text in hand-drawn diagrams from the article of the same name. For instance with the following image :
Here the in hand-drawn diagrams are showed with the red arrows which are not part of the document. The authors of the given article also used
The whole point of the project is to classify area of an image by entropy with python in order to be able to select only paragraphs that have these drawn [.
My attempt
Inspired by this post I thought about :
doing a Canny edge detection selecting the pixels close to black or grey
Focus on a region of interest that minimizes false positives. This region of interest is basically the letters or shape without any of the black tape that covers one of their sides.
As you can imagine the arrays, which are of no interest, will create some issues.
Find all distinct contours which are close the one from the others.
Unfortunately I am already stuck at the first step : the Canny edge detection doesn't seem to be useful for text :
Here is the related code :
img = cv2.imread('out4.jpg',0)
edges = cv2.Canny(img,100,200,True)
plt.subplot(121),plt.imshow(img,cmap = 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(edges,cmap = 'gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])
plt.show()
So I tried to select only grey pixels but I had a ValueError: conversion from RGB to rgb not supported

Resources