I am currently stuck on detecting the hough lines in a precalculated NumPy array.
However, it seems like I cannot figure out, why OpenCV doesn't accept the NumPy array to work with and detect the lines.
The error message refers to the input channels, even so, I thought this should be detected automatically since OpenCV uses NumPy arrays natively.
I provided a minimum working example below.
However, the line detection might fail because of the random values.
import numpy as np
import cv2
from matplotlib import pyplot as plt
format = 50
img = np.random.choice([0, 1], size=(format,format), p=[1/30, 29/30])
plt.imshow(img, interpolation='nearest')
plt.show()
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,50,150,apertureSize = 3)
minLineLength = 100
maxLineGap = 10
lines = cv2.HoughLinesP(edges,1,np.pi/180,100,minLineLength,maxLineGap)
for x1,y1,x2,y2 in lines[0]:
cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2)
cv2.imshow('image',img)
cv2.waitKey(0)
Error Message:
> cv2.error: OpenCV(4.2.0)
> ../modules/imgproc/src/color.simd_helpers.hpp:92: error:
> (-2:Unspecified error) in function
> 'cv::impl::{anonymous}::CvtHelper<VScn, VDcn, VDepth,
> sizePolicy>::CvtHelper(cv::InputArray, cv::OutputArray, int) [with
> VScn = cv::impl::{anonymous}::Set<3, 4>; VDcn =
> cv::impl::{anonymous}::Set<1>; VDepth = cv::impl::{anonymous}::Set<0,
> 2, 5>; cv::impl::{anonymous}::SizePolicy sizePolicy =
> cv::impl::<unnamed>::NONE; cv::InputArray = const cv::_InputArray&;
> cv::OutputArray = const cv::_OutputArray&]'
> Invalid number of channels in input image:
> 'VScn::contains(scn)'
> where
> 'scn' is 1
Edit:
I know the problem is with the numpy array being of binary data (0 or 1), but I don't know how to read it in to be handled properly.
As written in the comments there are several flaws in your code.
Use an image size where Houghline has a chance to find lines.
For an image the np.random.choise array has to be converted to unit8.
The result can be used as grayscale image.
The colour "white" in grayscale image has value 255.
If you want to draw colours, you have to convert your image to BGR.
White noise will hardly lead to detected lines. I have intentionally drawn a line through the noise to demonstrate, that houghlines can distinguish this line from the noise.
You can use this working example to start from and edit it step by step to what you actually want to do.
import numpy as np
import cv2
f = 500
img = np.random.choice([255, 0], size=(f, f), p=[1/30, 29/30]).astype("uint8")
cv2.line(img, (50, 50), (100, 300), 255, 2)
cv2.imshow('image', img)
cv2.waitKey(0)
minLineLength = 100
maxLineGap = 40
lines = cv2.HoughLinesP(img, 1, np.pi/180, 100, minLineLength, maxLineGap)
img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
if lines is not None:
for x1, y1, x2, y2 in lines[0]:
cv2.line(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
cv2.imshow('image', img)
cv2.waitKey(0)
Output:
Related
I want to detect the width (in pixels) of any car in front of me. So, I tried to extract the horizontal lines which is supposed to correspond to its width. Below is my approach:
input image :
import cv2
from google.colab.patches import cv2_imshow
import numpy as np
from google.colab.patches import cv2_imshow
image = cv2.imread('croopped.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 250, apertureSize=3)
cv2_imshow(edges)
kernel = np.ones((1,5))
linh = cv2.erode(edges,kernel)
cv2_imshow(linh)
lines = cv2.HoughLinesP(linh, 1, np.pi/180, 10, maxLineGap= 50, minLineLength = 50)
if lines is not None:
for line in lines:
x1, y1, x2, y2 = line[0]
cv2.line(image, (x1, y1), (x2, y2), (0, 255, 0), 3)
cv2_imshow(image)
As you can see the lines are not as expected (to get a good horizontal line corresponds to its width)
expected results:
How can I fine tune/use different approach to get better horizontal lines?
You can try getting the vertical lines instead, and then measure their distance as shown in the code:
kernel = np.ones((1,5))
linh = cv2.erode(edges,kernel)
cv2_imshow(linh)
Not sure how you would modify the code for that case though.
I have a program in a jupyter notebook that uses k means to segment an image by using dominant color color clusters. It works well, now I try to add some code from a PyCharm program that draws lines on the image using thresholding. Now I am getting this error at the bottom.
!pip install opencv-python
!pip install sklearn
import numpy as np
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import cv2
image = cv2.imread('C:\\Users\\holli\\OneDrive\\Pictures\\python photos\\lau black short changing room, haair.jpg')
image.shape
x,y,z= image.shape
plt.imshow(image)
img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
plt.imshow(img)
img = img.reshape(-1,3)
dominant_color = 6
model = KMeans(dominant_color)
model.fit(img)
colors = model.cluster_centers_
colors = np.array(colors, dtype="uint8")
colors
colors = np.array(colors, dtype="uint8")
for i in range(new_image.shape[0]):
new_image[i] = colors[model.labels_[i]]
new_image = np.reshape(new_image, (x,y,z))
plt.imshow(new_image)
model.labels_
blurred = cv2.medianBlur(img, 5)
grey_blur = cv2.cvtColor(blurred, cv2.cv2.COLOR_BGR2GRAY)
thresh = cv2.adaptiveThreshold(grey_blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 15, 5)
combined = cv2.bitwise_and(new_image, new_image, mask=thresh)
cv2.imshow("cartoon Lau blk shrt", combined)
reg_img = cv2.cvtColor(new_image, cv2.COLOR_RGB2BGR)
cv2.imwrite('C:\\Users\\holli\\OneDrive\\Pictures\\python photos\\lai_img_seg.jpg', reg_img)
---------------------------------------------------------------------------
error Traceback (most recent call last)
<ipython-input-78-9346139ce50d> in <module>
1 blurred = cv2.medianBlur(img, 5)
----> 2 grey_blur = cv2.cvtColor(blurred, cv2.cv2.COLOR_BGR2GRAY)
3 thresh = cv2.adaptiveThreshold(grey_blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 15, 5)
4 combined = cv2.bitwise_and(new_image, new_image, mask=thresh)
5 cv2.imshow("cartoon Lau blk shrt", combined)
error: OpenCV(4.5.3) c:\users\runneradmin\appdata\local\temp\pip-req-build-c2l3r8zm\opencv\modules\imgproc\src\color.simd_helpers.hpp:92: error: (-2:Unspecified error) in function '__cdecl cv::impl::`anonymous-namespace'::CvtHelper<struct cv::impl::`anonymous namespace'::Set<3,4,-1>,struct cv::impl::A0xb6623f80::Set<1,-1,-1>,struct cv::impl::A0xb6623f80::Set<0,2,5>,2>::CvtHelper(const class cv::_InputArray &,const class cv::_OutputArray &,int)'
> Invalid number of channels in input image:
> 'VScn::contains(scn)'
> where
> 'scn' is 1
I think that I may be able to write/save the "blurred" image then read it back in and perform the other tasks on it. If that doesn't work I will not know what else to do.
Can anyone see anything in my code that might cause this "invalid number of channels in input image:" error?
img has an unsuitable shape.
If you want it to be BGR (for cvtColor), it must be (something, something, 3).
After your reshaping (flattening), it only has two dimensions because you gave it the shape (-1, 3)... which cvtColor interprets to mean a single-channel (grayscale) image.
You could reshape it to be (-1, 1, 3), which is a long column of color pixels:
img.shape = (-1, 1, 3)
I'm attempting to parse floorplans to turn them into an array of line coordinates using HoughLinesP in opencv-python and the function is only returning lines that are angled and have no relation to the actual lines in my image.
Here is my code:
import cv2
# Read image and convert to grayscale
img = cv2.imread('C:/Data/images/floorplan/extremely basic.png', -1)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Get lines with probabilistic hough lines
found_lines = cv2.HoughLinesP(gray, 1, 3.14 / 160, 100,
minLineLength=1, maxLineGap=10)
# Loop through found lines and draw each line on original image
for line in found_lines:
x1, y1, x2, y2 = line[0]
cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 1)
# Show image, wait until keypress, close windows.
cv2.imshow('image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
And here is what's going to be returned with threshold 150 and 100 respectively:
I've tried tinkering with all options and attempted non-probabilistic Hough lines to no avail.
The problem was with image inversion and parameters. You have to do further adjustments as this does not give all lines.
The code is test on google colab. Remove from google.colab.patches import cv2_imshow and replace cv_imshow with cv2.imshow for local usage.
Partial Image Ouput
Code
import cv2
import numpy as np
from google.colab.patches import cv2_imshow
# Read image and convert to grayscale
img = cv2.imread('1.jpg', 0)
#gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
s1, s2 = img.shape
new_img = np.zeros([s1,s2],dtype=np.uint8)
new_img.fill(255)
ret,thresh1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)
cv2_imshow(thresh1)
kernel = np.ones((3,3),np.uint8)
erosion = cv2.erode(thresh1,kernel,iterations = 1)
cv2_imshow(erosion)
# Get lines with probabilistic hough lines
found_lines = cv2.HoughLinesP(erosion, np.pi/180, np.pi/180, 10, minLineLength=4, maxLineGap=4)
# Loop through found lines and draw each line on original image
for line in found_lines:
x1, y1, x2, y2 = line[0]
cv2.line(new_img, (x1, y1), (x2, y2), (0, 0, 255), 1)
cv2_imshow(new_img)
#cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 1)
# Show image, wait until keypress, close windows.
print("ORIGINAL IMAGE:")
cv2_imshow(img)
#cv2.imshow('image', img)
#cv2.waitKey(0)
#cv2.destroyAllWindows()
I have following image: named 'Normalised.png'. I am trying to draw solid lines from dotted lines.
I have tried approaches like hough line transform:
import cv2
import numpy as np
img = cv2.imread('Normalised.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,50,150,apertureSize = 3)
minLineLength = 100
maxLineGap = 10
lines = cv2.HoughLinesP(edges,1,np.pi/180,100,minLineLength,maxLineGap)
for x1,y1,x2,y2 in lines[0]:
cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2)
cv2.imwrite('houghlines5.jpg',img)
But it appears that the code fails on 'edges' as no 'edges' are detected.
Input image
Expected Output Image
How do I achieve this output?
By default, HoughLinesP works for straight lines. However, you can detect curves by using cv2.HOUGH_PROBABILISTIC as follows:
img = cv.imread("Dilate.png")
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
edges = cv.Canny(gray, 150, 200, apertureSize=3)
cv.imwrite("Canny.png", edges)
element = cv.getStructuringElement(cv.MORPH_RECT, (5, 3), (-1, -1))
dilated = cv.dilate(edges, element)
cv.imwrite("Eroded.png", dilated)
minLineLength = 200
maxLineGap = 5
lines = cv.HoughLinesP(dilated, cv.HOUGH_PROBABILISTIC, np.pi/180, 150, minLineLength,
maxLineGap)
for x in range(0, len(lines)):
for x1, y1, x2, y2 in lines[x]:
pts = np.array([[x1, y1], [x2, y2]], np.int32)
cv.polylines(img, [pts], True, (0, 255, 0))
cv.imwrite('dilate_final.png', img)
Note how the lines are being drawn.
Result is not exactly what you want but close and requires you to tune the parameters which I will leave for you. Hope it helps!
A possible scheme (though the whole task seems desperate):
choose a small number of directions (say 5) uniformly spread;
for every direction,
smooth in that direction (f.i. with a very elongated Gaussian) or
erode in that direction (with a linear structuring element), or both, to better connect the dots,
binarize with threshold such that the dots come in contact,
apply morphological thickening to get thin black lines.
combine all maps so obtained (max operation),
cleanup.
I am trying to segment circles in a DICOM image. I am trying to implement the hough transform with opencv to do so. I am getting this error:
cv2.error: OpenCV(4.1.0) /Users/travis/build/skvark/opencv-python/opencv/modules/imgproc/src/hough.cpp:1736: error: (-215:Assertion failed) !_image.empty() && _image.type() == CV_8UC1 && (_image.isMat() || _image.isUMat()) in function 'HoughCircles'
Code:
#Segment circle code using openCV
def segment_circles(self):
image = np.float(self.image)
output = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1.2, 100)
if circles is not None:
circles = np.round(circles[0, :].astype("int"))
for (x, y, r) in circles:
cv2.circle(output, (x,y), r, (0, 255, 0), 4)
cv2.rectangle(output, (x - 5, y - 5), (x + 5, y + 5), (0, 128, 255), -1)
cv2.imshow("output", np.hstack([image, output]))
cv2.waitKey(0)
#how self.image is created in another function
self.image = PIL.Image.fromarray(numpy_array)
Thank you in advance for your help.
Here is a workflow that can be used to read a DICOM file from disk and perform the Hough transform
import pydicom
import cv2
import numpy as np
# read the DICOM file
d16=pydicom.read_file('view0010.dcm')
print(f"original data type={d16.pixel_array.dtype}")
# rescale original 16 bit image to 8 bit values [0,255]
x0=d16.pixel_array.min()
x1=d16.pixel_array.max()
y0=0
y1=255.0
i8=((d16.pixel_array-x0)*((y1-y0)/(x1-x0)))+y0
# create new array with rescaled values and unsigned 8 bit data type
o8=i8.astype(np.uint8)
print(f"rescaled data type={o8.dtype}")
# do the Hough transform
h=cv2.HoughCircles(o8, cv2.HOUGH_GRADIENT, 1.2, 100)
print(f"h={h}")
When I run this with a real MR image on my computer here is the output ...
original data type=int16
rescaled data type=uint8
h=[[[172.20001 259.80002 154.92001]
[319.80002 273. 161.64 ]]]
Of course the results of the Hough transform will be different for you, but i think it shows what has to be done to run the cv2 HoughCircles function on a real DICOM image.
Well I think I would add a few lines of code after the “gray = ... “ line to test each of those conditions individually. Do you know for sure that gray().isEmpty() is really false? Just take a minute or two to find out which conditions are failing the validation test.
What modality is the image?
Please see Wilf's answer for proper fix.
Quick fix of original code:
def hough_circles(self):
#load image
img = self.imager.values[self.imager.index, :, :]
image8 = np.uint8(img)
output = image8.copy()
#apply hough transform
circles = cv2.HoughCircles(image8, cv2.HOUGH_GRADIENT, 1.2, 100)
#place circles and cente rectangle on image
if circles is not None:
circles = np.round(circles[0, :].astype("int"))
for (x, y, r) in circles:
cv2.circle(output, (x,y), r, (0, 255, 0), 4)
cv2.rectangle(output, (x - 5, y - 5), (x + 5, y + 5), (0, 128, 255), -1)
cv2.imshow("output", np.hstack([image8, output]))
cv2.waitKey(0)