Вопрос или проблема
Я хочу реализовать пользовательское вычисление цвета для таблицы поиска цветов. Я создал подкласс vtkColorTransferFunction
и переопределил функции GetColor
и MapValue
. Но цвет не меняется, независимо от того, использую ли я оригинальный vtkColorTransferFunction
или мой подкласс. Более того, функции, которые я переопределил, не вызывались ядром VTK. Как мне реализовать пользовательское вычисление цвета?
from vtkmodules.vtkRenderingCore import (
vtkActor,
vtkDataSetMapper,
vtkRenderWindow,
vtkRenderWindowInteractor,
vtkRenderer
)
from vtkmodules.vtkRenderingCore import (
vtkColorTransferFunction
)
from vtkmodules.vtkCommonDataModel import (
VTK_QUAD,
vtkUnstructuredGrid,
)
from vtkmodules.vtkCommonCore import vtkPoints
from vtk.numpy_interface import dataset_adapter as dsa
from typing import Tuple, MutableSequence
import math
import numpy as np
class LogarithmicColorTransferFunction(vtkColorTransferFunction):
def __init__(self):
super().__init__()
self.originalMin = 0
self.originalMax = 1
def SetOriginalRange(self, min, max):
self.originalMin = min
self.originalMax = max
def MapValue(self, v:float):
print(v) # Просто заглушка вывода, но никогда не выполнялась
return super().MapValue(v)
def GetBlueValue(self, x:float):
print(x) # Просто заглушка вывода, но никогда не выполнялась
return super().GetBlueValue(x)
def GetColor(self, x:float) -> Tuple[float, float, float]:
print(x) # Никогда не выполнялась
log = math.log
exp = math.exp
a = self.originalMin
b = self.originalMax
y = -((log(a)-log(b*x-a*x+a))/(log(b)-log(a)))
# y = (exp(x*(log(b)-log(a))+log(a))-a) / (b-a)
return super().GetColor(y)
def GetColor(self, x:float, rgb:MutableSequence[float]) -> None:
print(x) # Никогда не выполнялась
c = self.GetColor(x)
rgb[:] = c
def main():
ctf = LogarithmicColorTransferFunction()
ctf.SetColorSpaceToRGB()
ctf.SetScaleToLinear()
ctf.SetNanColor(0.0, 0.0, 0.0)
table = np.array([
[0, 0.01, 0.043, 1],
[0.2, 0.641, 0.164, 0.725],
[0.3, 0.988, 0.051, 0.11],
[0.5, 1, 0.975, 0.5],
[0.8, 1, 1, 1],
[1, 1, 1, 1]
])
for point in table:
ctf.AddRGBPoint(*point)
ctf.SetOriginalRange(1, 5)
points = vtkPoints()
ugrid = vtkUnstructuredGrid()
data = np.array([[0, 0, 0,],
[10, 0, 0],
[10, 10, 0],
[0, 10, 0]])
points.SetData(dsa.numpyTovtkDataArray(data))
quad = [0,1,2,3]
ugrid.InsertNextCell(VTK_QUAD, 4, quad)
ugrid.SetPoints(points)
c = np.array([0, 1, 2, 3])/3
ugrid.GetPointData().SetScalars(dsa.numpyTovtkDataArray(c))
mapper = vtkDataSetMapper()
mapper.SetInputData(ugrid)
mapper.SetLookupTable(ctf)
actor = vtkActor()
actor.SetMapper(mapper)
renderer = vtkRenderer()
renderWindow = vtkRenderWindow()
renderWindow.AddRenderer(renderer)
renderWindowInteractor = vtkRenderWindowInteractor()
renderWindowInteractor.SetRenderWindow(renderWindow)
renderer.AddActor(actor)
renderWindow.Render()
renderWindowInteractor.Start()
if __name__ == '__main__':
main()
Ответ или решение
Подклассирование vtkColorTransferFunction для реализации пользовательской цветовой карты
Ваша задача заключается в создании подкласса для vtkColorTransferFunction
, чтобы реализовать собственное вычисление цвета в цветовой карте. Вы столкнулись с тем, что переопределенные функции такие как GetColor
и MapValue
не вызываются VTK, и, как следствие, изменения цвета не проявляются. Давайте рассмотрим основные шаги, которые помогут вам правильно реализовать эту задачу.
1. Основы VTK
Перед тем как перейти кSubclassing, неплохо бы понять, как VTK обрабатывает цветовые преобразования. Как правило, VTK использует собственные алгоритмы для обработки RGB значений, включая функции отображения (GetColor
, MapValue
и т. д.). Ваш подкласс должен быть правильно интегрирован в эту архитектуру.
2. Обработка цветовой карты
При создании собственного класса для color transfer function, важно убедиться, что он правильно взаимодействует с остальной частью системы VTK:
- Переопределение методов: Вы переопределили методы, но не убедились, что они действительно используются в контексте вашего визуализационного процесса.
- Использование вашего подкласса: Убедитесь, что вы используете экземпляр вашего подкласса в методах, которые требуют работы с цветовой картой.
3. Пример реализации
Вот как можно изменить ваш код, чтобы он работал корректно:
from vtkmodules.vtkRenderingCore import (
vtkActor,
vtkDataSetMapper,
vtkRenderWindow,
vtkRenderWindowInteractor,
vtkRenderer
)
from vtkmodules.vtkRenderingCore import (
vtkColorTransferFunction
)
from vtkmodules.vtkCommonDataModel import (
VTK_QUAD,
vtkUnstructuredGrid,
)
from vtkmodules.vtkCommonCore import vtkPoints
from vtk.numpy_interface import dataset_adapter as dsa
from typing import Tuple, MutableSequence
import math
import numpy as np
class LogarithmicColorTransferFunction(vtkColorTransferFunction):
def __init__(self):
super().__init__()
self.originalMin = 1
self.originalMax = 5
def SetOriginalRange(self, min_val: float, max_val: float):
self.originalMin = min_val
self.originalMax = max_val
def MapValue(self, v: float) -> float:
if v < self.originalMin or v > self.originalMax:
return super().MapValue(v) # Возврат значения по стандартному пути
# Применение логарифмического преобразования
norm_value = (v - self.originalMin) / (self.originalMax - self.originalMin)
log_value = math.log(1 + norm_value * (math.e - 1)) # Логарифм от стандартизированного значения
return super().MapValue(log_value)
def GetColor(self, x: float) -> Tuple[float, float, float]:
rgb = [0.0, 0.0, 0.0]
if x < self.originalMin or x > self.originalMax:
return super().GetColor(x) # Возврат значения по стандартному пути
norm_value = (x - self.originalMin) / (self.originalMax - self.originalMin)
log_value = math.log(1 + norm_value * (math.e - 1))
return super().GetColor(log_value)
def GetColor(self, x: float, rgb: MutableSequence[float]) -> None:
rgb[:] = self.GetColor(x)
def main():
ctf = LogarithmicColorTransferFunction()
ctf.SetColorSpaceToRGB()
table = np.array([
[0, 0.01, 0.043, 1],
[0.2, 0.641, 0.164, 0.725],
[0.3, 0.988, 0.051, 0.11],
[0.5, 1, 0.975, 0.5],
[0.8, 1, 1, 1],
[1, 1, 1, 1]
])
for point in table:
ctf.AddRGBPoint(*point)
ctf.SetOriginalRange(0, 1)
points = vtkPoints()
ugrid = vtkUnstructuredGrid()
data = np.array([[0, 0, 0],
[10, 0, 0],
[10, 10, 0],
[0, 10, 0]])
points.SetData(dsa.numpyTovtkDataArray(data))
quad = [0, 1, 2, 3]
ugrid.InsertNextCell(VTK_QUAD, 4, quad)
ugrid.SetPoints(points)
c = np.array([0, 1, 2, 3]) / 3
ugrid.GetPointData().SetScalars(dsa.numpyTovtkDataArray(c))
mapper = vtkDataSetMapper()
mapper.SetInputData(ugrid)
mapper.SetLookupTable(ctf)
actor = vtkActor()
actor.SetMapper(mapper)
renderer = vtkRenderer()
renderWindow = vtkRenderWindow()
renderWindow.AddRenderer(renderer)
renderWindowInteractor = vtkRenderWindowInteractor()
renderWindowInteractor.SetRenderWindow(renderWindow)
renderer.AddActor(actor)
renderWindow.Render()
renderWindowInteractor.Start()
if __name__ == '__main__':
main()
Заключение
Убедитесь, что ваш подкласс действительно используется в процессе визуализации и правильно обрабатывает значения на выходе. Важными моментами являются правильная настройка диапазонов значений и внедрение ваших методов в VTK. Если после этих изменений все равно не работает, убедитесь, что внешние зависимости и версии библиотек совместимы с вашим кодом.