Converting dask array using np.asarry is very slow - python

I have a folder of about 150 large images (40000x30000x3) ~400MB each, and I want to validate ROIs from an imaging analysis. I was looking to store the file information in a dask array and then index the specific section of the image by converting it to a numpy array.
import dask_image.imread
import numpy as np
from PIL import ImageTk, Image, ImageDraw
lazy_signal = dask_image.imread.imread(os.path.join(path, '*.jpeg'))
for roi in rois:
z, y_range, x_range = roi[:]
img = lazy_signal.[z,
y_range[0]:y_range[1],
x_range[0]:x_range[1],
:]
img = np.asarray(img)
img = Image.fromarray(img)
img = img.resize((200, 200))
draw = ImageDraw.Draw(img)
draw.ellipse((85, 85, 115, 115), outline = (0, 0, 255), width = 1)
img.imshow()
However, the conversion to an numpy array is taking multiple seconds per roi and the image chunk is only (100, 100, 3). Any idea how to speed this up or just go straight from dask.array to image?

Related

Error, while opening Numpy array in OpenCV

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:

Convert series of images into an array using OpenCV and convert the RGB array to gray scale

Hi I'm trying to convert a series of images into an array and then convert the RGB to gray scale.
In my work folder I have x number of frames.png, I need to read all this frames in an array and then convert each frame (RGB) to Gray scale.
For one frame my code is:
import numpy as np
import cv2 as cv
from PIL import Image
# Read image
Image = cv.imread('frame0.png')
# RGB to Gray Scale
GS = cv.cvtColor(Image, cv.COLOR_BGR2GRAY)
th, Gray = cv.threshold(GS, 128, 192, cv.THRESH_OTSU)
Any idea?
You can use os to read files from a folder. With the "endswith" function, you can extract file formats and pull them all.
Here is a working code
import numpy as np
import cv2 as cv
import os
for file in os.listdir("/mydir"): # images folder path
if file.endswith((".png",".jpg")): # you can add formats
img = cv.imread(file)
GS = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
th, Gray = cv.threshold(GS, 128, 192, cv.THRESH_OTSU)
cv.imwrite("converted-"+file,Gray)

Trying to save image from numpy array with PIL, getting errors

trying to save an inverted image, saved inverted RGB colour data in array pixelArray, then converted this to a numpy array. Not sure what is wrong but any help is appreciated.
from PIL import Image
import numpy as np
img = Image.open('image.jpg')
pixels = img.load()
width, height = img.size
pixelArray = []
for y in range(height):
for x in range(width):
r, g, b = pixels[x, y]
pixelArray.append((255-r,255-b,255-g))
invertedImageArray = np.array(pixelArray, dtype=np.uint8)
invertedImage = Image.fromarray(invertedImageArray, 'RGB')
invertedImage.save('inverted-image.jpeg')
img.show()
getting error code "ValueError : not enough image data"
Your np.array creates an array shape (4000000, 3) instead of (2000, 2000, 3).
Also, you may find that directly mapping the subtraction to the NumPy array is faster and easier
from PIL import Image
import numpy as np
img = Image.open('image.jpg')
pixelArray = np.array(img)
pixelArray = 255 - pixelArray
invertedImageArray = np.array(pixelArray, dtype=np.uint8)
invertedImage = Image.fromarray(invertedImageArray, 'RGB')
invertedImage.save('inverted-image.jpeg')
PIL already provides an easier way to invert the image colours with the ImageOps module.
from PIL import Image, ImageOps
img = Image.open('image.jpg')
invertedImage = ImageOps.invert(img)
invertedImage.save('inverted-image.jpeg')

Numpy, PIL doesn't invert PNG image

I was doing a course which taught data science; it had a portion on using NumPy arrays for image inversion. It's able to invert jpg, but isn't able to invert PNG, I tried other images with the same extension, it doesn't work on those which have "png" extension (it only shows a transparent image).
What can be the problem? Thank you!
from PIL import Image
from IPython.display import display
#displaying the image
img = Image.open(r"./download.png")
display(img)
#converting the image into an array
imgArray = np.array(img)
imgArrayShape = imgArray.shape
#inverting the image
fullArray = np.full(imgArrayShape, 255)
invertedImageArray = abs(fullArray - imgArray)
invertedImageArray = invertedImageArray.astype(np.uint8)
#displaying the inverted image
invertedImage = Image.fromarray(invertedImageArray)
display(invertedImage)
As far as I could tell, the problem was, that you inverted the Alpha Channel as well.
The following code adaptation works on my end:
from PIL import Image
import numpy as np
#displaying the image
img = Image.open("test.png")
img.show()
#converting the image into an array
imgArray = np.array(img)
imgArrayShape = imgArray.shape
#inverting the image
fullArray = np.full(imgArrayShape, [255, 255, 255, 0])
invertedImageArray = abs(fullArray - imgArray)
invertedImageArray = invertedImageArray.astype(np.uint8)
#displaying the inverted image
invertedImage = Image.fromarray(invertedImageArray)
invertedImage.show()

How can I speed up this image mask creation process in python?

I need to create masks for 100.000 images, this code runs on cpu and creates ~500 masks a hour. Is there a way I can speed this up either by parallelising or running code on gpu? I'm okay with solutions that make me heavily rewrite code as long as it speeds up the process.
I tried compiling opencv library myself with cuda support, however I couldn't get most of cv2 methods I use here to run on gpu.
This is my code
Edit #1
Added import list and comments to code.
Added input and output images.
import cv2
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
import glob
import sys
import os
import skimage.color
import skimage.filters
import skimage.io
import skimage.viewer
grayScale = cv2.imread(filename,cv2.IMREAD_REDUCED_GRAYSCALE_4)#read image as grayscale with size reduction
kernel = cv2.getStructuringElement(1,(17,17))
blackhat = cv2.morphologyEx(grayScale, cv2.MORPH_BLACKHAT, kernel)
ret,thresh2 = cv2.threshold(blackhat,10,255,cv2.THRESH_BINARY)
dst = cv2.inpaint(newimg,thresh2,1,cv2.INPAINT_TELEA) #4 lines above are used to remove hair from image
mask = np.zeros(dst.shape[:2],np.uint8)
h,w,c = dst.shape
bgdModel = np.zeros((1,65),np.float64)
fgdModel = np.zeros((1,65),np.float64)
rect = (int(0.1*w),int(0.1*h),int(0.8*w),int(0.8*h))
cv2.grabCut(dst,mask,rect,bgdModel,fgdModel,1,cv2.GC_INIT_WITH_RECT) #removes some background from image
#code for k means clustering starts here
mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
dst = dst*mask2[:,:,np.newaxis]
vectorized = dst.reshape((-1,3))
vectorized = np.float32(vectorized)
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0) #11 lines above are used to remove some background from image
K = 4
attempts=1
ret,label,center=cv2.kmeans(vectorized,K,None,criteria,attempts,cv2.KMEANS_PP_CENTERS)
center = np.uint8(center)
labels = label.flatten()
res = center[label.flatten()]
result_image = res.reshape((dst.shape)) #k means clustering ends here
gray = cv2.cvtColor(result_image, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 10, 20, cv2.THRESH_BINARY)
result_image[thresh == 0] = 255
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
erosion = cv2.erode(result_image, kernel, iterations = 1)
blur = skimage.color.rgb2gray(erosion)
blur = skimage.filters.gaussian(blur, sigma=float(1))
histogram, bin_edges = np.histogram(blur, bins=256, range=(0, 1))
index = next((i for i, x in enumerate(histogram) if x), None)
mask = blur > bin_edges[index+1] #10 lines above are used to create mask
mask = abs(mask-255) #inverts mask
array = np.array(mask, dtype='uint8')
finimg = cv2.resize(array,None,fx=4.0,fy=4.0) #returns image to original size
plt.imsave("Masks/"+filename, finimg, cmap = plt.cm.gray) #saves result image
input image - skin mole image
output image - mask of skin mole
You might try using kmeans processing in Python/Opencv as a first step. Then get the inner contour and use that for your mask. Draw the inner contour as white filled on a black background. You may need to use morphology to clean the kmeans results first
Input:
Kmeans 2:
Kmeans 3:
Kmeans 4:

Categories

Resources