将阈值应用于图像(快速)
Apply a threshold to an image (quickly)
我正在尝试构建一个支持阈值处理的像素计数程序。我希望用户能够快速生成输入图像区域的预览,程序将在量化期间考虑这些区域 "positive"。
输入:
输入图像将是 24 位 RGB TIFF 文件(叠加 3 个通道)或 16 位灰度 TIFF(每个通道一个图像,位深度更大)。用户将 select 他们正在加载的图像类型("mode" 变量),他们感兴趣的频道("desiredcolour" 变量(RGB 为 0-2))和他们想要使用的阈值("self.threshold" 变量)。输入图像分辨率约为 1400x1000。
输出:
单击 "Preview" 按钮后,用户选择一个文件,然后会弹出 window 显示该图像的预览,其中正像素覆盖浅蓝色。我无法在程序 window 中显示 16 位灰度 tiff,所以我在生成预览时将它们转换为 RGB。将颜色应用于检测到的像素的能力在那里很有用。我还让它将预览调整为更方便的大小。
虽然下面的脚本有效,但理想情况下,我希望在用户更改阈值变量时更新预览图像。当前的脚本需要几秒钟才能生成图像,因此这并不理想。
目前我的主要功能如下:
import tkinter as tk
import tkinter.filedialog as tkfiledialog
from PIL import Image, ImageTk
打开预览window
def openpreview(self):
global desiredcolour
self.previewfile = Image.open(tkfiledialog.askopenfilename())
self.logevent("Opening preview")
self.genpreview(self.previewfile, desiredcolour)
阈值预览生成器
def genpreview(self, tgt, value):
global mode
self.pixellist = list(tgt.getdata())
self.newlist=[]
if mode.get() == "RGB" and tgt.mode[0] == "I":
self.logevent("Error: This is not an RGB file")
return
elif mode.get() == "RAW" and tgt.mode[0] != "I":
self.logevent("Error: This doesn't look like a RAW file")
return
for point in self.pixellist:
if mode.get() == "RGB":
if point[value] >= self.threshold.get():
point = (0, 191, 255)
self.newlist.append(point)
if mode.get() == "RAW":
if point >= self.threshold.get():
point = (0, 191, 255)
else:
point = point//255
point = (point, point, point)
self.newlist.append(point)
self.preview = Image.new("RGB", tgt.size)
self.preview.putdata(self.newlist)
self.preview = self.preview.resize((tgt.size[0]//2, tgt.size[1]//2))
self.preview = ImageTk.PhotoImage(self.preview)
self.preview_window(self.preview)
在新的 window
中显示预览
def preview_window(self, outgoingimage):
self.previewwindow = tk.Toplevel()
self.previewwindow.wm_attributes('-toolwindow',1)
self.previewpane = tk.Label(self.previewwindow, image=outgoingimage)
self.previewpane.image=outgoingimage
self.previewpane.grid(row=1, column=1)
我想知道我是否以错误的方式处理这个问题,是否有更有效的方法来完成这一切?也可能是哪里出错了。
在尝试了几种不同的方法之后,我最终想到的最快的方法是使用 Numpy 和 opencv 包。使用数组而不是遍历像素要高效得多,此版本每张图像花费约 0.05 秒,而不是上面脚本的约 0.9 秒。
阈值预览生成器
def genpreview(self, tgt, value):
activemode = mode.get()
thold = threshold.get()
imfile = cv2.imread(tgt, -1)
if activemode == "RGB" and imfile.dtype != "uint8":
self.logevent("Error: This is not an RGB file")
return
elif activemode == "RAW" and imfile.dtype != "uint16":
self.logevent("Error: This doesn't look like a RAW file")
return
if activemode == "RGB":
mask = (imfile[:,:,value] > thold)
imfile[mask] = (0, 191, 255)
self.preview2 = Image.fromarray(imfile, 'RGB')
self.preview = self.preview2.resize((self.preview2.size[0] // 2, self.preview2.size[1] // 2))
elif activemode == "RAW":
im = cv2.imread(tgt)
mask = (im[:,:,1] > thold//256)
im[mask] = (0, 191, 255)
self.preview2 = Image.fromarray(im, 'RGB')
self.preview = self.preview2.resize((self.preview2.size[0] // 2, self.preview2.size[1] // 2))
self.preview = ImageTk.PhotoImage(self.preview)
对于输入,“tgt”只是目标文件路径的字符串,“value”是正在分析的通道的索引。
我正在尝试构建一个支持阈值处理的像素计数程序。我希望用户能够快速生成输入图像区域的预览,程序将在量化期间考虑这些区域 "positive"。
输入:
输入图像将是 24 位 RGB TIFF 文件(叠加 3 个通道)或 16 位灰度 TIFF(每个通道一个图像,位深度更大)。用户将 select 他们正在加载的图像类型("mode" 变量),他们感兴趣的频道("desiredcolour" 变量(RGB 为 0-2))和他们想要使用的阈值("self.threshold" 变量)。输入图像分辨率约为 1400x1000。
输出:
单击 "Preview" 按钮后,用户选择一个文件,然后会弹出 window 显示该图像的预览,其中正像素覆盖浅蓝色。我无法在程序 window 中显示 16 位灰度 tiff,所以我在生成预览时将它们转换为 RGB。将颜色应用于检测到的像素的能力在那里很有用。我还让它将预览调整为更方便的大小。
虽然下面的脚本有效,但理想情况下,我希望在用户更改阈值变量时更新预览图像。当前的脚本需要几秒钟才能生成图像,因此这并不理想。
目前我的主要功能如下:
import tkinter as tk
import tkinter.filedialog as tkfiledialog
from PIL import Image, ImageTk
打开预览window
def openpreview(self):
global desiredcolour
self.previewfile = Image.open(tkfiledialog.askopenfilename())
self.logevent("Opening preview")
self.genpreview(self.previewfile, desiredcolour)
阈值预览生成器
def genpreview(self, tgt, value):
global mode
self.pixellist = list(tgt.getdata())
self.newlist=[]
if mode.get() == "RGB" and tgt.mode[0] == "I":
self.logevent("Error: This is not an RGB file")
return
elif mode.get() == "RAW" and tgt.mode[0] != "I":
self.logevent("Error: This doesn't look like a RAW file")
return
for point in self.pixellist:
if mode.get() == "RGB":
if point[value] >= self.threshold.get():
point = (0, 191, 255)
self.newlist.append(point)
if mode.get() == "RAW":
if point >= self.threshold.get():
point = (0, 191, 255)
else:
point = point//255
point = (point, point, point)
self.newlist.append(point)
self.preview = Image.new("RGB", tgt.size)
self.preview.putdata(self.newlist)
self.preview = self.preview.resize((tgt.size[0]//2, tgt.size[1]//2))
self.preview = ImageTk.PhotoImage(self.preview)
self.preview_window(self.preview)
在新的 window
中显示预览def preview_window(self, outgoingimage):
self.previewwindow = tk.Toplevel()
self.previewwindow.wm_attributes('-toolwindow',1)
self.previewpane = tk.Label(self.previewwindow, image=outgoingimage)
self.previewpane.image=outgoingimage
self.previewpane.grid(row=1, column=1)
我想知道我是否以错误的方式处理这个问题,是否有更有效的方法来完成这一切?也可能是哪里出错了。
在尝试了几种不同的方法之后,我最终想到的最快的方法是使用 Numpy 和 opencv 包。使用数组而不是遍历像素要高效得多,此版本每张图像花费约 0.05 秒,而不是上面脚本的约 0.9 秒。
阈值预览生成器
def genpreview(self, tgt, value):
activemode = mode.get()
thold = threshold.get()
imfile = cv2.imread(tgt, -1)
if activemode == "RGB" and imfile.dtype != "uint8":
self.logevent("Error: This is not an RGB file")
return
elif activemode == "RAW" and imfile.dtype != "uint16":
self.logevent("Error: This doesn't look like a RAW file")
return
if activemode == "RGB":
mask = (imfile[:,:,value] > thold)
imfile[mask] = (0, 191, 255)
self.preview2 = Image.fromarray(imfile, 'RGB')
self.preview = self.preview2.resize((self.preview2.size[0] // 2, self.preview2.size[1] // 2))
elif activemode == "RAW":
im = cv2.imread(tgt)
mask = (im[:,:,1] > thold//256)
im[mask] = (0, 191, 255)
self.preview2 = Image.fromarray(im, 'RGB')
self.preview = self.preview2.resize((self.preview2.size[0] // 2, self.preview2.size[1] // 2))
self.preview = ImageTk.PhotoImage(self.preview)
对于输入,“tgt”只是目标文件路径的字符串,“value”是正在分析的通道的索引。