I have a tiff file of 3 channel 16 bit images. I would like to convert them to 8 bit 3 channel images but when i do a simple scaling i find that those images which are predominantly red turn all black. Is there a way to do this conversion while preserving color of the original 16 bit images. Right now i have this code.
for r in root_:
files = os.listdir(r)
for f in files:
if "tif" in f[-3:]:
filepath = r+"/"+f
tif = TIFFfile(filepath)
samples, sample_names = tif.get_samples()
test = np.moveaxis(samples[0], 0, 2)
img8 = (test/256).astype('uint8')
I am guessing you want to apply adaptive range adjustment.
Linear "stretching" between some global minimum and global maximum is a simple solution.
Finding lower and upper percentile is more robust solution than minimum and maximum.
Here is an example:
import cv2
import numpy as np
# Build input image for testing
test = cv2.imread('chelsea.png').astype(np.uint16) * 100
# lo - low value as percentile 0.1 (1/1000 of test values are below lo)
# hi - high value as percentile 99.9 (1/1000 of test values are above hi)
lo, hi = np.percentile(test, (0.1, 99.9))
# Apply linear "stretech" - lo goes to 0, and hi goes to 255
img8 = (test.astype(float) - lo) * (255/(hi-lo))
#Clamp range to [0, 255] and convert to uint8
img8 = np.maximum(np.minimum(img8, 255), 0).astype(np.uint8)
#Display images before and after linear "stretech":
cv2.imshow('test', test)
cv2.imshow('img8', img8)
cv2.waitKey(0)
cv2.destroyAllWindows()
Result:
test:
img8:
Try to revise your question so less guessing is required.
Please let me know if my guess was right.
I would extract the 3 channels:
c1 = test[:,:][0]
c2 = test[:,:][1]
c3 = test[:,:][2]
Scale them to 8bit with a helper function:
def bytescale(image, cmin=None, cmax=None, high=255, low=0):
if image.dtype == np.uint8:
return image
if high > 255:
high = 255
if low < 0:
low = 0
if high < low:
raise ValueError("`high` should be greater than or equal to `low`.")
if cmin is None:
cmin = image.min()
if cmax is None:
cmax = image.max()
cscale = cmax - cmin
if cscale == 0:
cscale = 1
scale = float(high - low) / cscale
bytedata = (image - cmin) * scale + low
return (bytedata.clip(low, high) + 0.5).astype(np.uint8)
Do scaling on channels:
c1new = bytescale(c1)
c2new = bytescale(c2)
c3new = bytescale(c3)
Put all back together:
x = np.array([c1new, c2new, c3new])
Let me know if this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With