Image Cropping to get just the particular shape out of image - python-3.x

[I have the images as below, i need to extract just the white strip portion from all the images.
i Have tried using PIL to extract the rectangular portion by manually specifying the pixel value, Can there be any automated way to get this work done where by just feeding the image gives back the rectangular portion
Below is My snipped code:
from PIL import Image
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = Image.open('C:/Users/ShAgarwal/Documents/image_dataset/pic9.jpg')
half_the_width = img.size[0] / 2
half_the_height = img.size[1] / 2
img4 = img.crop(
(
half_the_width-1632,
half_the_height - 440,
half_the_width+1632,
half_the_height + 80
)
)
sample image

import cv2
import numpy as np
from matplotlib import pyplot as plt
image='IMG_3134.JPG'
# read image
imgc = cv2.imread(image)
img = cv2.resize(imgc, None, fx=0.25, fy=0.25) # resize since image is huge
#cropping the strip dimensions
#crop_img = img[1010:1650,140:1099723]
blurred = cv2.blur(img, (3,3))
canny = cv2.Canny(blurred, 50, 200)
Marking coordinates through auto image detection using canny's algorithm
## find the non-zero min-max coords of canny
pts = np.argwhere(canny>0)
y1,x1 = pts.min(axis=0)
y2,x2 = pts.max(axis=0)`
`## crop the region
cropped = img[y1:y2, x1:x2]
cv2.imwrite("cropped.png", cropped)
#Select the bounded area around white boundary
tagged = cv2.rectangle(img.copy(), (x1,y1), (x2,y2), (0,255,0), 3, cv2.LINE_AA)
r = cv2.selectROI(tagged)
imCrop = im[int(r[1]):int(r[1]+r[3]), int(r[0]):int(r[0]+r[2])]
#Bounded Area
cv2.imwrite("taggd2.png", imcrop)
cv2.waitKey()
Results from above code

Related

why does opencv threshold returns absurd output on a very simple image?

I am trying to count seeds in an image using cv2 thresholding. The test image is below:
When I run the below code to create a mask:
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('S__14278933.jpg')
#img = cv2.fastNlMeansDenoisingColored(img,None,10,10,7,21)
mask = cv2.threshold(img[:, :, 0], 255, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
plt.imshow(mask)
I get the following mask:
But ideally it should give a small yellow dot at the centre. I have tried this with other images and it works just fine.
Can someone help?
The lighting in your image seems not uniform. Try using Adaptive Thresholding:
import cv2
import numpy as np
# image path
path = "D://opencvImages//"
fileName = "c6pBO.jpg"
# Reading an image in default mode:
inputImage = cv2.imread(path + fileName)
# Convert the image to grayscale:
grayImage = cv2.cvtColor(inputImage, cv2.COLOR_BGR2GRAY)
# Get binary image via Adaptive Thresholding :
windowSize = 31
windowConstant = 40
binaryImage = cv2.adaptiveThreshold( grayImage, 255, cv2.ADAPTIVE_THRESH_MEAN_C,
cv2.THRESH_BINARY_INV, windowSize, windowConstant )
cv2.imshow("binaryImage", binaryImage)
cv2.waitKey(0)
You might want to apply an Area Filter after this, though, as dark portions on the image will yield noise.
Try it
img=cv2.imread('foto.jpg',0)
mask = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV )[1]

Remove Freckles from Simple Binary Image

I have the following NumPy array of a running man, which you can download here:
https://drive.google.com/file/d/1SfIEqGsBV_vA7iP4UjLdklLJlLdDzozL/view?usp=sharing
To display it, use this code:
import numpy as np
import matplotlib.pyplot as plt
# load data
data = np.load('running_man.npy')
# plot data
plt.imshow(data)
As you can see there is a lot of noise (freckles) in the image. I would like to get rid of it and retrieve a clean image of the runner. Any idea of how to do it?
This is what I have done so far:
from skimage import measure
# Find contours at a constant value of 1
contours = measure.find_contours(data, 1, fully_connected='high')
# Select the largest contiguous contour
contour = sorted(contours, key=lambda x: len(x))[-1]
# Create an empty image to store the masked array
r_mask = np.zeros_like(data, dtype='bool')
# Create a contour image by using the contour coordinates rounded to their nearest integer value
r_mask[np.round(contour[:, 0]).astype('int'), np.round(contour[:, 1]).astype('int')] = 1
# Fill in the hole created by the contour boundary
r_mask = ndimage.binary_fill_holes(r_mask)
# Invert the mask since one wants pixels outside of the region
r_mask = ~r_mask
plt.imshow(r_mask)
... but as you can see the outline is very rough !
What works well is to upload the image to an online jpg to SVG converter -> this makes the lines super smooth. ... but I want to be able to do it in python.
Idea:
I am looking for something that can keep the sharp corners, maybe something that detects the gradient along the edge and only keeps the point where the gradient is above a certain threshold...
For this specific image you can just use numpy:
import numpy as np
import matplotlib.pyplot as plt
data = np.load('running_man.npy')
data[data > 1] = 0
plt.xticks([])
plt.yticks([])
plt.imshow(data)
For a method that preserves the corners better, we can use median filters, but force the preservation of corners.
Masked Image
Mask after filtering
Recolored
import cv2
import numpy as np
# load image
img = cv2.imread("run.png");
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY);
# make mask
_, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU);
# median filter
med = cv2.medianBlur(thresh, 11);
med[thresh == 255] = 255;
# inverse filter
mask = cv2.bitwise_not(med);
med = cv2.medianBlur(mask, 3);
med[mask == 255] = 255;
# recolor
color = np.zeros_like(img);
color[med == 0] = (66, 239, 245);
color[med == 255] = (92, 15, 75);
# show
cv2.imshow("colored", color);
cv2.waitKey(0);

Convert image to ndarray and vice-versa

I have this image and following python code.
import numpy as np
from PIL import Image
image = Image.open("File.png")
image = image.convert("1")
image.show()
bw = np.asarray(image).copy()
im01 = np.where(bw, 0, 1)
new_img = Image.fromarray(im01)
new_img.show()
Since the image is black and white, I could see the im01 as a 2D ndarray with 0s and 1 as white and black pixels in 184x184 matrix.
Why didn't Image.fromarray() work?
Is there something that I am missing?

Smoothing jagged edges of an image

I would like to generate a skeleton out of an image. Since the edges that are generated using skimage from the original image isn't smooth, the resulting skeleton obtained from binary has disconnected edges with knots.
import skimage
from skimage import data,io,filters
import numpy as np
import cv2
import matplotlib.pyplot as plt
from skimage.filters import threshold_adaptive,threshold_mean
from skimage.morphology import binary_dilation
from skimage import feature
from skimage.morphology import skeletonize_3d
imgfile = "edit.jpg"
image = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
thresh = threshold_mean(image)
binary = image > thresh
edges = filters.sobel(binary)
dilate = feature.canny(binary,sigma=0)
skeleton = skeletonize_3d(binary)
fig, axes = plt.subplots(nrows=2,ncols=2, figsize=(8, 2))
ax = axes.ravel()
ax[0].imshow(binary, cmap=plt.cm.gray)
ax[0].set_title('binarize')
ax[1].imshow(edges, cmap=plt.cm.gray)
ax[1].set_title('edges')
ax[2].imshow(dilate, cmap=plt.cm.gray)
ax[2].set_title('dilates')
ax[3].imshow(skeleton, cmap=plt.cm.gray)
ax[3].set_title('skeleton')
for a in ax:
a.axis('off')
plt.show()
I tried using dilate to smoothen the jagged edges. But the contours in the skeleton has two edges instead of a single edge that is desired.
I would like to ask for suggestions on how the edges can be smoothened to avoid knots and disconnected edges in the resulting skeleton.
Input image
Output images
Edit:After using gaussian smoothing
binary = image > thresh
gaussian = skimage.filters.gaussian(binary)
skeleton = skeletonize_3d(gaussian)
This median filter should do the work on your binary image for the skeletonization.
import scipy
binary_smoothed = scipy.signal.medfilt (binary, 3)
For the borders, I will probably use this and play with the parameters as shown in the link below
https://claudiovz.github.io/scipy-lecture-notes-ES/advanced/image_processing/auto_examples/plot_canny.html:
from image_source_canny import canny
borders = canny (binary_smoothed, 3, 0.3, 0.2)

How to detect Roads from satellite images and get the outline using opencv python

Hey guys, I am trying to detect roads from satellite images.
After identifying the roads am getting the co-ordinates like roads coordinates and building coordinates.
The code which i tried to extract roads from satellite images.
Input image
from __future__ import print_function, division
from PIL import Image
import operator
import cv2
from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
#reading image directly from current working directly
build_image = cv2.imread("avilla_san_marcos_gilbert,az.png")
#Doing MeanShift Filtering
#shifted = cv2.pyrMeanShiftFiltering(image, 21, 51)
#GrayScale Conversion
build_gray = cv2.cvtColor(build_image, cv2.COLOR_BGR2GRAY)
#OTSU Thresholding
thresh = cv2.threshold(build_gray, 0, 255,
cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv2.imshow("OTSU Thresholded Image",thresh)
cv2.imwrite("OTSU_1 image.jpg",thresh)
#Checking Coordinates of White Pixels
build_white = np.argwhere(thresh == 255)
#Creating an array
build_data= np.array(build_white)
np.savetxt('build_coords.csv', build_data,delimiter=",")
#Checking Coordinates of White Pixels
road_white = np.argwhere(thresh == 0)
#Creating an array
road_data = np.array(road_white)
print(road_data)
#Saving vector of roads in a csv file
np.savetxt('road_coords.csv', road_data,delimiter=",")
Output image is plotted based on csv of Road pixel Coordinates
I have a problem with the output image obtained. It has detected trees i have to eliminate it by obtaining the pixel coordinates of tree.
So From that output image i have to extract the layout of the roads alone.Please try to help me out guys. Thanks in advance.

Resources