How to use openCV to change white to black? - python

I have a bean on a white background damper, the issue is that the damper is not perfectly white (as in 255,255,255). I have tried using cv2.threshold() method but I kept getting a deformed image with spots. What is the best way to achieve this?
My Image
My Code
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY)
img[thresh == 255] = 0
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
erosion = cv2.erode(img, kernel, iterations = 1)
cv2.namedWindow('image', cv2.WINDOW_NORMAL)
cv2.imshow("image", erosion)
In the end, the beans should only be surrounded by black images!

It could be the solution:
import cv2
import numpy as np
img = cv2.imread("data/bob.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_blured = cv2.blur(gray, (5, 5))
ret, thres = cv2.threshold(img_blured, 130, 255, cv2.THRESH_BINARY)
neg = cv2.bitwise_not(thres)
erosion = cv2.erode(neg, np.ones((6, 6), np.uint8), iterations=1)
cv2.imshow("erosion", erosion)
# ret, thresh = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY)
img[erosion == 0] = 0
cv2.imshow("image", img)
cv2.waitKey(0)
Here I am using cv2.threshold but for bigger range than you used, but before it I blured the image. Then I negate and erode it.
But this cuts off the bean itself a little, if this is critical, then you should use a completely different algorithm. For example, the cv2.Canny method to find the contours of a bean and somehow further process it.

Related

How can I remove black dots around hand in image

using opencv for capturing image in python
i want to make this image :
code for this :
# Image Processing
gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (51,51), 15)
th3 = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)
ret, test_image = cv2.threshold(th3, 10, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
to somewhat like this:
If you'll consider Scikit-Image, instead of OpenCV, here's an approach. It has been edited from my original post, thanks to guiding commentary from #Yves Daoust. This more correct approach runs significantly faster
import numpy as np
import matplotlib.pyplot as plt
from skimage import io
from skimage import filters
from skimage import morphology
threshold = filters.threshold_otsu(image)
bimage = np.where(image>threshold,255,0)
rsh_img = morphology.remove_small_holes(bimage,area_threshold=33)
I think you should try closing operation. It will do the work.
gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (51,51), 15)
th3 = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)
ret, test_image = cv2.threshold(th3, 10, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
kernel = np.ones((3, 3), np.uint8)
# opening the image
opening = cv2.morphologyEx(binr, cv2.MORPH_OPEN,
kernel, iterations=1)
If the resultant image is not good enough then try to increase he kernal size

What settings in cv2.threshold() to threshold this image?

I would like to convert this image to gray scale in OpenCV and then find the settings to threshold it. I want to threshold the black spaces inside of the skull. Can someone write out a Python script using OpenCV?
I convert to grayscale with: gray = cv2.cvtColor(pic, cv2.COLOR_BGR2GRAY)
When I do (ret, thresh) = cv2.threshold(gray, 177, 255, cv2.THRESH_BINARY) I get a black image.
When I do (ret, thresh) = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY) the whole head becomes a white blob.
If i has understood your goal correctly, here is my proposal. It uses Otsu's Thresholding as #stateMachine has said.
import cv2
im = cv2.imread("IScDg.png")
gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# Your first method
(_, thresh1) = cv2.threshold(gray, 177, 255, cv2.THRESH_BINARY)
# Your second method
(ret, thresh2) = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)
# Proposed method
(_, thresh3) = cv2.threshold(gray, 0, 1, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
different thresholds on your image
I usually apply OTSU with good results.
ret,gray = cv2.threshold(gray,100,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

Detect thin line in an image

I'm having a hard time detecting the thin black line in the following image. I tried all sort of opencv processing and applied findContours, but wasn't able to catch this. Is anyone able to help plz?
For example I tried this:
import cv2
img = cv2.imread('SampleLine.png')
# convert img to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, thresh_type, block, constant)
# apply morphology open then close
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (1,1))
blob = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (10,10))
blob = cv2.morphologyEx(blob, cv2.MORPH_CLOSE, kernel)
# invert blob
blob = (255 - blob)
cnts,hierarchy = cv2.findContours(blob, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img, cnts, -1, (0, 0, 255), 3)
cv2.imwrite("output_Line.png", img)
I'm looking for an output like this:

How to select child contour in OpenCV and increase accuracy using python

I'm really new to OpenCV. :) I have been working on this for almost an entire day. After hours of sleepless work I would like to know if I can further improve my code.
I have written some code to select only the black markings on the images. These black markings are child contours. Whilst my code is able to select some contours, it isn't accurate. You can see the code draws contours around the shadows along with black markings.
Code 1
At first I tried to use canny edge detection. But I was unable to overlay with the original image correctly.
import cv2
import numpy as np
image = cv2.imread('3.jpg')
image = cv2.resize(image, (500, 500))
image2 = image
cv2.waitKey(0)
# Grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Find Canny edges
edged = cv2.Canny(gray, 30, 200)
cv2.waitKey(0)
contours, hierarchy = cv2.findContours(edged, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cv2.imshow('Canny', edged)
cv2.waitKey(0)
# print("Number of Contours found = " + str(len(contours)))
cv2.drawContours(image2, contours, -1, (0, 255, 0), 3)
cv2.imshow('Contours', image2)
cv2.waitKey(0)
cv2.destroyAllWindows()
Code 2
I was able to improve on Code 1 to be far more accurate. You should be able to see that it now only selects half of the thumb, none of the other fingers and it doesn't select the indent on the background.
Additionally changing the background of the image also increases the accuracy of the result.
import cv2
import numpy as np
image = cv2.imread('3.jpg', 0)
image2 = cv2.imread('3.jpg')
image = cv2.resize(image, (500, 500))
image2 = cv2.resize(image2, (500, 500))
cv2.waitKey(0)
ret, thresh_basic = cv2.threshold(image, 100, 255, cv2.THRESH_BINARY)
cv2.imshow("Thresh basic", thresh_basic)
# Taking a matrix of size 5 as the kernel
kernel = np.ones((5, 5), np.uint8)
img_erosion = cv2.erode(thresh_basic, kernel, iterations=1)
#####################
ret, thresh_inv = cv2.threshold(img_erosion, 100, 255, cv2.THRESH_BINARY_INV)
cv2.imshow("INV", thresh_inv)
#####################
# Find Canny edges
edged = cv2.Canny(img_erosion, 30, 200)
cv2.waitKey(0)
contours, hierarchy = cv2.findContours(edged, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cv2.imshow('Canny', edged)
cv2.waitKey(0)
# print("Number of Contours found = " + str(len(contours)))
cv2.imshow('Original', image2)
cv2.drawContours(image2, contours, -1, (0, 255, 0), 3)
cv2.imshow('Contours', image2)
cv2.waitKey(0)
cv2.destroyAllWindows()
Can I improve my code further?

Count gear (Python, OpenCV)

For a prototype I need to build a 3d model of a gear. This have a "many" number of teeth.
So I am trying to count them using OpenCV and Python. I found this (only?) post which explain how to do it in C++.
I am following the steps and, for now this is the code I made.
import numpy as np
import cv2
img = cv2.imread('C:\\Users\\Link\\Desktop\\gear.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
kernel = np.ones((3, 3), np.uint8)
img_erosion = cv2.erode(thresh, kernel, iterations=1)
edges = cv2.Canny(img_erosion, 50, 150)
img_dilate = cv2.dilate(edges, kernel, iterations=1)
cv2.imshow('i', thresh)
cv2.waitKey(0)
cv2.imshow('i', img_erosion)
cv2.waitKey(0)
cv2.imshow('i', edges)
cv2.waitKey(0)
cv2.imshow('i', img_dilate)
cv2.waitKey(0)
What stopped me from go ahead is this: the image at some point became really a mess.
This is the original on which I am working:
And this is the output of image_dilate
As you can see, the teeth at the bottom is not displayed properly, maybe because of the shaddow in the original image. How can I get rid of this ?
Because your source image is cleaner than the link your post, so you can do approx on the max-area-contour, then get half number of points, the result is 84.
Sample code:
#!/usr/bin/python3
# 2018.01.22 11:53:24 CST
import cv2
import myutils
## Read
img = cv2.imread("img13_2.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
## threshold and find contours
ret, threshed = cv2.threshold(gray, 50, 255, cv2.THRESH_BINARY_INV)
cnts= cv2.findContours(threshed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2]
## Find the max-area-contour
cnt = max(contours, key=cv2.contourArea)
## Approx the contour
arclen = cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, 0.002*arclen, True)
## Draw and output the result
for pt in approx:
cv2.circle(img, (pt[0][0],pt[0][1]), 3, (0,255,0), -1, cv2.LINE_AA)
msg = "Total: {}".format(len(approx)//2)
cv2.putText(img, msg, (20,40),cv2.FONT_HERSHEY_PLAIN, 2, (0,0,255), 2, cv2.LINE_AA)
## Display
cv2.imshow("res", img);cv2.waitKey()
Result:
Solved it..
This is the code. The count is wrong by one because one teeth, on the right is lower than the others and because it found two points by itself. Don't know why this happens.
Also, it has been made with another image. It's not the source I posted above as long as it is in low definition.
import numpy as np
import cv2
img = cv2.imread('C:\\Users\\Link\\Desktop\\gear.png')
img2 = cv2.imread('C:\\Users\\Link\\Desktop\\gear.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
kernel = np.ones((3, 3), np.uint8)
img_dilate = cv2.dilate(thresh, kernel, iterations=1)
im2, contours, hierarchy = cv2.findContours(img_dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cv2.drawContours(img, contours, -1, (0, 255, 0), -1)
edges = cv2.Canny(cnts, 350, 350)
cnt = contours[0]
hull = cv2.convexHull(cnt, returnPoints=False)
defects = cv2.convexityDefects(cnt, hull)
for i in range(defects.shape[0]):
s, e, f, d = defects[i, 0]
start = tuple(cnt[s][0])
end = tuple(cnt[e][0])
far = tuple(cnt[f][0])
cv2.line(edges, start, end, [0, 255, 255], 1)
circles = cv2.circle(img2, end, 5, [0, 255, 0], -1)
# print(len(defects)) - number of points
cv2.imshow('thresh', thresh)
cv2.waitKey(0)
cv2.imshow('dilate', img_dilate)
cv2.waitKey(0)
cv2.imshow('edges', edges)
cv2.waitKey(0)
cv2.imshow('cnts', cnts)
cv2.waitKey(0)
cv2.imshow('points', circles)
cv2.waitKey(0)

Categories

Resources