DICOM image is not read correctly - python

I have a dicom file from which I read images. The images I read, however, has incorrect colormap. Ideally, the image should look like:
However, the following code only gives me
If I only take the red component, I get the image below, which is not correct and cannot be adjusted to the ideal result in any colormap I tried.
or
root = tk.Tk()
root.withdraw()
path = filedialog.askopenfilename()
ds = dicom.dcmread(path, force = True) # reads a file data set
video = ds.pixel_array #reads a sequence of RGB images
plt.imsave(some_path, video[0], format='png') #gives image [2]
What have I done wrong?

This really looks like YCbCr data, is the Photometric Interpretation something like YBR_FULL? If so then as mentioned in the documentation you need to apply a colour space conversion, which in pydicom is:
from pydicom import dcmread
from pydicom.pixel_data_handlers import convert_color_space
ds = dcmread(...)
rgb = convert_color_space(ds.pixel_array, "YBR_FULL", "RGB")

Related

Remove header with sensitive information from dicom file

I would like to transform the pixels of the header of a dicom image (which contains sensitive information) to pixel value = 0 (black background).
I can do that with the following code:
import pydicom
from pydicom import dcmread
fn = "A0000.dcm"
ds = dcmread(fn)
# Three channels
ds.pixel_array[0:68, 0:1280, 0] = 0
ds.pixel_array[0:68, 0:1280, 1] = 0
ds.pixel_array[0:68, 0:1280, 2] = 0
# Plot image
plt.imshow(ds.pixel_array, cmap="gray")
# Save
ds.save_as("dicom_processed")
When I run imshow, the header is removed, however when I save the dicom file, the header is not remove
EDIT: The header is like an image
I would like something like this, in an easy way (removing all the background):
https://microsoft.github.io/presidio/image-redactor/
https://medium.com/data-science-at-microsoft/redacting-sensitive-text-from-dicom-medical-images-in-python-ab35a34a10c0
This does not work:
ds.remove_private_tags()

Can't open an image from URL in opencv

I'm working on a program that reads csv file to get the names of colors, compares RGB values with RGB values of an image from URL. I think the program doesn't get image from URL since I tried to imshow() to check whether image is passed into program or not. I get this error
(-215:Assertion failed) size.width>0 && size.height>0 in function 'imshow'
This is the code:
import numpy as np #needed to work with matrix of an image
import pandas as pd #needed to work with color.csv
import cv2 #needed to work with image
import matplotlib.pyplot as pl #needed to work with plotting
import urllib.request#needed to work with image url
#step 1. Read csv file with name, RGB and HEX values.
#step 2. Set color detection function. Get value of pixels in a NumPy array
#step 3. Compare RGB value of a pixel with dataframe.
#step 4. Save the name and RBG value inside a file.
#image from url
def url_to_image(url): #doesn't get file, need to work upon this
resp = urllib.request.urlopen(url)
image = np.asarray(bytearray(resp.read()), dtype='uint8')
image = cv2.imdecode(image,cv2.IMREAD_COLOR)
return image
#dataframe with 864 colors
index = ['color', 'color_name', 'hex','R','G','B']
csv = pd.read_csv('colors.csv', names = index, header = None)
def getColor(R,G,B):
minimum = 10000
for i in range(len(csv)):
distance = abs(R-int(csv.loc[i, 'R'])) + abs(G-int(csv.loc[i, 'G'])) + abs(B-int(csv.loc[i,'B']))
if(distance<=minimum):
minimum = distance
color_name = csv.loc[i, 'color_name']
return color_name
img = url_to_image("https://upload.wikimedia.org/wikipedia/commons/2/24/Solid_purple.svg")
cv2.imshow("image", img)
cv2.waitKey(0)
It doesn't work because you are trying to use an svg Image (which is vector based) to open in an Matrix like an JPEG or PNG image (which are raster based). It doesn't work like that with these.
Try loading a different Image like this
https://miro.medium.com/max/800/1*bNfxs62uJzISTfuPlOzOWQ.png EDIT sry wrong link
https://htmlcolorcodes.com/assets/images/colors/purple-color-solid-background-1920x1080.png
this will work because this is an png
As far as i know Opencv has no good support for SVG based Images

How can I successfully display this PNG image pulled from an array? (Poor understanding of PIL)

I am trying to store a set of png images in an array and later display them when needed. I am initially importing png files from local storage and storing as type '_io.BytesIO'.
I can then create an object of type 'PIL.PngImagePlugin.PngImageFile' using Image.open() which responds to display().
See working code:
byts = import_png(raw_string)
im = Image.open(byts)
display(im)
def import_png(raw_string):
"""input = string, output = '_io.BytesIO' type
The output is to be displayable as image for testing and storable in array"""
byteImgIO = io.BytesIO()
byteImg = Image.open(raw_string)
byteImg.save(byteImgIO, "PNG")
byteImgIO.seek(0)
byteImg = byteImgIO.read()
dataBytesIO = io.BytesIO(byteImg)
return dataBytesIO
I am failing to do the above for multiple png's stored in an array. See below:
array = np.zeros((3,24,24)) #3 test images of size 24x24 pixels
for id in range (0,3):
byts = import_png(raw_string)
im = Image.open(byts)
array[id] = im
test_id = 0
array[test_id] = array[test_id].astype(np.uint8) #ensuring correct datatype
im = Image.fromarray(array[test_id]) # produces type 'PIL.Image.Image' with mode = 'F'
if im.mode != 'RGB':
im = im.convert('RGB')
print(str(im)) #Gives <PIL.Image.Image image mode=RGB size=24x24 at 0x1DEEDCB72B0>
display(im) # Fails to display by just showing black box
I know that something is going wrong with the data conversion, as curiously running the line below adjusts the image to be almost the original.
array[test_id] = 255-(array[test_id]*255/8)
Edit: #mark-setchell
I’ll try to be more clear. The ultimate goal of this block of code is to import png files from my computer and store them efficiently such that they can be displayed and used to train a neural network.
I had trouble simply importing the images for display, hence my code to convert to ‘_io.BytesIO’ for display.
Also I was unable to write the Bytes object to an array hence the confusing flow where I convert back to image with im = Image.open(byts).
If you can suggest the pythonic way to get rid of the above I would be grateful.
Given your comment about mode ‘F’ being inconsistent with a png file I think I may have a mistake in the following code:
im = Image.open(byts)
array[test_id] = array[test_id].astype(np.uint8) #ensuring correct datatype
im = Image.fromarray(array[test_id])
The above code creates a 'PIL.Image.Image' mode = 'F' rather than the 'PIL.PngImagePlugin.PngImageFile' which successfully displays.
Edit #2
The goal remains the same. I want to take a folder of 10000 png files (RGBA) and efficiently read them and carry out some basic deep learning.
I have fixed my initial hacky code such that dealing with bytes is not needed, with code below. A key fix was recognizing that the correct mode is RGBA.
def image_id_to_image(id):
"""Input = id integer,
Output = RGBA image file of shape (24, 24, 4)"""
raw_str = image_id_to_raw_str(id)
im = Image.open(raw_str)
#display(im) #if you wish to check whats going on
im = im.convert('RGBA')
return im
I have also now managed to store all 10000 .png files in a .h5 file for more convenient and efficient reading.
def store_many_hdf5(images, labels):
""" Stores an array of images to HDF5.
Parameters:
---------------
images images array, (N, 24, 24, 4) to be stored
labels labels array, (N, 1) to be stored
"""
num_images = len(images)
# Create a new HDF5 file
hdf5_dir = fr"PATH"
file = h5py.File(hdf5_dir, "w")
# Create a dataset in the file
dataset = file.create_dataset(
"images", np.shape(images), h5py.h5t.STD_U8BE, data=images
)
meta_set = file.create_dataset(
"meta", np.shape(labels), h5py.h5t.STD_U8BE, data=labels
)
file.close()
test_img_count =6
image_array = np.zeros((test_img_count,24,24,4))
labels = np.zeros((test_img_count,1))
for i in range(0,test_img_count):
image = image_id_to_image(i)
image_array[i,:,:,:] = image
labels[i] = "%03d" % i
store_many_hdf5(images = image_array, labels = labels)
I have also managed to successfully display multiple images from the created h5 file
hdf5_dir = fr"PATH.h5"
multi_image_hdf5 = h5py.File(hdf5_dir, "r")
multi_images = np.array(multi_image_hdf5["images"])
multi_labels = np.array(multi_image_hdf5["meta"])
filename = hdf5_dir
fig, axes = plt.subplots(2,3, figsize=(24,24))
for i,ax in enumerate(axes.flat):
ax.imshow(multi_images[i].astype(np.uint8))

How to retain the colors of a PNG image when converting back from an array

Whenever I convert a PNG image to a np.array and then convert it back to a PNG I lose all the colors of the image. I would like to be able to retain the colors of the original PNG when I am converting it back from a np.array.
Original PNG Image
My code:
from PIL import Image
im = Image.open('2007_000129.png')
im = np.array(im)
#augmenting image
im[0,0] = 1
im = Image.fromarray(im, mode = 'P')
Outputs a black and white version of the image
I also try using getpalette and putpalette but this does not work it just returns a NonType object.
im = Image.open('2007_000129.png')
pat = im.getpalette()
im = np.array(im)
im[0,0] = 1
im = Image.fromarray(im, mode = 'P')
im= im.putpalette(pat)
Your image is using single channel color using palette. Try the code below. Also you can check more about this subject at What is the difference between images in 'P' and 'L' mode in PIL?
from PIL import Image
import numpy as np
im = Image.open('gsmur.png')
rgb = im.convert('RGB')
np_rgb = np.array(rgb)
p = im.convert('P')
np_p = np.array(p)
im = Image.fromarray(np_p, mode = 'P')
im.show()
im2 = Image.fromarray(np_rgb)
im2.show()
Using the second code provided, the error comes from this line:
im= im.putpalette(pat)
If you refer to the documentation of Image.putpalette, you see that this function doesn't return any value, thus Image.putpalette is applied to the corresponding image directly. So, (re-)assigning the non-existent return value (which then is None) is not necessary – or, as seen here, erroneous.
So, the simple fix is just to use:
im.putpalette(pat)
Using this change, the second code provided works as intended.

Sticking two pictures together in python

Short question, I have 2 images. One is imported through:
Image = mpimg.imread('image.jpg')
While the other one is a processed image of the one imported above, this image is first converted from rgb to hls and then back. The outcome of this convertion gives a "list" which is different than the uint8 of the imported image.
When I'm trying to stick these images together with the function:
new_img2[:height,width:width*2]=image2
I don't see the second image in the combined image while by plotting the image through:
imgplot = plt.imshow(image2)
plt.show()
It works fine. What is the best way to convert the orignal to a "list" and then combine them or the "list" to uint8?
For some more information, the outcome has to be something like this:
enter image description here
Where the right side is black because the image I try to import in it has another type of array. The left image was an uint8 while the other is a "list". The second image is this one, which is saved from python:
enter image description here
Not sure how to do it the way you have show above but I have always been able to merge and save images as shown below!
def mergeImages(image1, image2, dir):
'''
Merge Image 1 and Image 2 side by side and delete the origional
'''
#adding a try/except would cut down on directory errors. not needed if you know you will always open correct images
if image1 == None:
image1.save(dir)
os.remove(image2)
return
im1 = Image.open(image1) #open image
im1.thumbnail((640,640)) #scales the image to 640, 480. Can be changed to whatever you need
im2 = Image.open(image2) #open Image
im1.thumbnail((640,480)) #Again scale
new_im = Image.new('RGB', (2000,720)) #Create a blank canvas image, size can be changed for your needs
new_im.paste(im1, (0,0)) #pasting image one at pos (0,0), can be changed for you
new_im.paste(im2, (640,0)) #again pasting
new_im.save(dir) #save image in defined directory
os.remove(image1) #Optionally deleting the origonal images, I do this to save on space
os.remove(image2)
After a day of searching I found out that both variables can be changed to the type of a float64. The "list" variable:
Image = np.asarray(Image)
This creates an float 64 from a List variable. While the uint8 can be changed to a float64 by:
Image2=np.asarray(Image2/255)
Than the 2 can be combined with:
totalImgage = np.hstack((Image,Image2))
Which than creates the wanted image.

Categories

Resources