本文整理汇总了Python中vtk.vtkCollection函数的典型用法代码示例。如果您正苦于以下问题:Python vtkCollection函数的具体用法?Python vtkCollection怎么用?Python vtkCollection使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。
在下文中一共展示了vtkCollection函数的20个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的Python代码示例。
示例1: setUp
def setUp(self):
self.vtkObjs = [vtk.vtkObject() for _ in range(30)]
self.collection = vtk.vtkCollection()
for obj in self.vtkObjs:
self.collection.AddItem(obj)
self.emptyCollection = vtk.vtkCollection()
开发者ID:ALouis38,项目名称:VTK,代码行数:7,代码来源:TestIterateCollection.py
示例2: examineForImport
def examineForImport(self,fileLists):
""" Returns a list of qSlicerDICOMLoadable
instances corresponding to ways of interpreting the
fileLists parameter.
"""
# Create loadables for each file list
loadables = []
for fileList in fileLists: # Each file list corresponds to one series, so do loadables
# Convert file list to VTK object to be able to pass it for examining
# (VTK class cannot have Qt object as argument, otherwise it is not python wrapped)
vtkFileList = vtk.vtkStringArray()
for file in fileList:
vtkFileList.InsertNextValue(slicer.util.toVTKString(file))
# Examine files
loadablesCollection = vtk.vtkCollection()
slicer.modules.dicomrtimportexport.logic().ExamineForLoad(vtkFileList, loadablesCollection)
for loadableIndex in xrange(0,loadablesCollection.GetNumberOfItems()):
vtkLoadable = loadablesCollection.GetItemAsObject(loadableIndex)
# Create Qt loadable if confidence is greater than 0
if vtkLoadable.GetConfidence() > 0:
# Convert to Qt loadable to pass it back
qtLoadable = slicer.qSlicerDICOMLoadable()
qtLoadable.copyFromVtkLoadable(vtkLoadable)
qtLoadable.tooltip = 'Valid RT object in selection'
qtLoadable.selected = True
loadables.append(qtLoadable)
return loadables
开发者ID:Sunderlandkyl,项目名称:SlicerRT,代码行数:30,代码来源:DicomRtImportExportPlugin.py
示例3: loadNode
def loadNode(self, uri, name, fileType = 'VolumeFile', fileProperties = {}):
self.logMessage('<b>Requesting load</b> <i>%s</i> from %s...\n' % (name, uri))
fileProperties['fileName'] = uri
fileProperties['name'] = name
firstLoadedNode = None
loadedNodes = vtk.vtkCollection()
success = slicer.app.coreIOManager().loadNodes(fileType, fileProperties, loadedNodes)
if not success or loadedNodes.GetNumberOfItems()<1:
self.logMessage('<b><font color="red">\tLoad failed!</font></b>\n')
return None
self.logMessage('<b>Load finished</b>\n')
# since nodes were read from a temp directory remove the storage nodes
for i in range(loadedNodes.GetNumberOfItems()):
loadedNode = loadedNodes.GetItemAsObject(i)
if not loadedNode.IsA("vtkMRMLStorableNode"):
continue
storageNode = loadedNode.GetStorageNode()
if not storageNode:
continue
slicer.mrmlScene.RemoveNode(storageNode)
loadedNode.SetAndObserveStorageNodeID(None)
return loadedNodes.GetItemAsObject(0)
开发者ID:millerjv,项目名称:Slicer,代码行数:27,代码来源:SampleData.py
示例4: addRuler
def addRuler(widget, color=None):
color = color if color else [0.25, 0.25, 0.75]
controller = widget.sliceController()
sliceView = widget.sliceView()
controller.setRulerType(2)
collection = vtk.vtkCollection()
sliceView.getDisplayableManagers(collection)
manager = None
for i in range(collection.GetNumberOfItems()):
if type(collection.GetItemAsObject(i)) is slicer.vtkMRMLRulerDisplayableManager:
manager = collection.GetItemAsObject(i)
break
renderers = manager.GetRenderer().GetRenderWindow().GetRenderers()
axisActor = None
textActor = None
for i in range(renderers.GetNumberOfItems()):
actors2D = renderers.GetItemAsObject(i).GetActors2D()
for j in range(actors2D.GetNumberOfItems()):
if type(actors2D.GetItemAsObject(j)) is vtk.vtkTextActor:
textActor = actors2D.GetItemAsObject(j)
elif type(actors2D.GetItemAsObject(j)) is vtk.vtkAxisActor2D:
axisActor = actors2D.GetItemAsObject(j)
if axisActor and textActor:
axisActor.GetProperty().SetColor(color)
textActor.GetProperty().SetColor(color)
sliceView.update()
break
开发者ID:QIICR,项目名称:Reporting,代码行数:31,代码来源:htmlReport.py
示例5: getModel3DDisplayableManager
def getModel3DDisplayableManager(self):
threeDViewWidget = slicer.app.layoutManager().threeDWidget(0)
managers = vtk.vtkCollection()
threeDViewWidget.getDisplayableManagers(managers)
for i in range(managers.GetNumberOfItems()):
obj = managers.GetItemAsObject(i)
if obj.IsA('vtkMRMLLinearTransformsDisplayableManager3D'):
return obj
return None
开发者ID:andrewfzheng,项目名称:Slicer,代码行数:9,代码来源:SlicerTransformInteractionTest1.py
示例6: export
def export(self, exportables):
exportablesCollection = vtk.vtkCollection()
for exportable in exportables:
vtkExportable = slicer.vtkSlicerDICOMExportable()
exportable.copyToVtkExportable(vtkExportable)
exportablesCollection.AddItem(vtkExportable)
self.exportAsDICOMSEG(exportablesCollection)
开发者ID:Sunderlandkyl,项目名称:Reporting,代码行数:9,代码来源:DICOMSegmentationPlugin.py
示例7: getFiducialSliceDisplayableManagerHelper
def getFiducialSliceDisplayableManagerHelper(self,sliceName='Red'):
sliceWidget = slicer.app.layoutManager().sliceWidget(sliceName)
sliceView = sliceWidget.sliceView()
collection = vtk.vtkCollection()
sliceView.getDisplayableManagers(collection)
for i in range(collection.GetNumberOfItems()):
m = collection.GetItemAsObject(i)
if m.GetClassName() == "vtkMRMLMarkupsFiducialDisplayableManager2D":
return m.GetHelper()
return None
开发者ID:kingofpanda,项目名称:Slicer,代码行数:10,代码来源:FiducialLayoutSwitchBug1914.py
示例8: export
def export(self,exportables):
# Convert Qt loadables to VTK ones for the RT export logic
exportablesCollection = vtk.vtkCollection()
for exportable in exportables:
vtkExportable = slicer.vtkSlicerDICOMExportable()
exportable.copyToVtkExportable(vtkExportable)
exportablesCollection.AddItem(vtkExportable)
# Export RT study
message = slicer.modules.dicomrtimportexport.logic().ExportDicomRTStudy(exportablesCollection)
return message
开发者ID:Sunderlandkyl,项目名称:SlicerRT,代码行数:11,代码来源:DicomRtImportExportPlugin.py
示例9: UpdateProxyNodeMetrics
def UpdateProxyNodeMetrics( taskMetrics, proxyNodes, time ):
if ( PythonMetricsCalculatorLogic.GetMRMLScene() == None or PythonMetricsCalculatorLogic.GetPerkEvaluatorLogic() == None ):
return
# Get all transforms in the scene
relevantTransformNodes = vtk.vtkCollection()
PythonMetricsCalculatorLogic.GetPerkEvaluatorLogic().GetProxyRelevantTransformNodes( proxyNodes, relevantTransformNodes )
# Update all metrics associated with children of the recorded transform
for j in range( relevantTransformNodes.GetNumberOfItems() ):
currentTransformNode = relevantTransformNodes.GetItemAsObject( j )
PythonMetricsCalculatorLogic.UpdateMetrics( taskMetrics, currentTransformNode, time )
开发者ID:mholden8,项目名称:PerkTutor,代码行数:12,代码来源:PythonMetricsCalculator.py
示例10: loadNodeFromFile
def loadNodeFromFile(filename, filetype, properties={}, returnNode=False):
from slicer import app
from vtk import vtkCollection
properties['fileName'] = filename
if returnNode:
loadedNodes = vtkCollection()
success = app.coreIOManager().loadNodes(filetype, properties, loadedNodes)
return success, loadedNodes.GetItemAsObject(0)
else:
success = app.coreIOManager().loadNodes(filetype, properties)
return success
开发者ID:gregsharp,项目名称:Slicer,代码行数:12,代码来源:util.py
示例11: testSubclassGhost
def testSubclassGhost(self):
"""Make sure ghosting of the class works"""
o = vtkCustomObject()
c = vtk.vtkCollection()
c.AddItem(o)
i = id(o)
del o
o = vtk.vtkObject()
o = c.GetItemAsObject(0)
# make sure the id has changed, but class the same
self.assertEqual(o.__class__, vtkCustomObject)
self.assertNotEqual(i, id(o))
开发者ID:timkrentz,项目名称:SunTracker,代码行数:12,代码来源:TestSubClass.py
示例12: widgetVisible
def widgetVisible(self, fidNode, viewNodeID):
lm = slicer.app.layoutManager()
for v in range(lm.threeDViewCount):
td = lm.threeDWidget(v)
ms = vtk.vtkCollection()
td.getDisplayableManagers(ms)
for i in range(ms.GetNumberOfItems()):
m = ms.GetItemAsObject(i)
if m.GetClassName() == "vtkMRMLMarkupsFiducialDisplayableManager3D" and m.GetMRMLViewNode().GetID() == viewNodeID:
h = m.GetHelper()
seedWidget = h.GetWidget(fidNode)
return seedWidget.GetEnabled()
return 0
开发者ID:sankhesh,项目名称:Slicer,代码行数:13,代码来源:MarkupsInViewsSelfTest.py
示例13: removeModelHierarchyAndChildModelNodesFromScene
def removeModelHierarchyAndChildModelNodesFromScene(modelHierarchyNode):
if modelHierarchyNode:
cmn = vtk.vtkCollection()
modelHierarchyNode.GetChildrenModelNodes(cmn)
for i in range(cmn.GetNumberOfItems()):
model = cmn.GetItemAsObject(i)
if model.IsA('vtkMRMLModelNode'):
slicer.mrmlScene.RemoveNode(model)
slicer.mrmlScene.RemoveNode(modelHierarchyNode)
开发者ID:QIICR,项目名称:LongitudinalPETCT,代码行数:13,代码来源:SlicerLongitudinalPETCTModuleViewHelper.py
示例14: makeModels
def makeModels(study, finding, colorTable):
if (study is None) | (finding is None) | (colorTable is None):
return
seg = finding.GetSegmentationMappedByStudyNodeID(study.GetID())
if seg:
labelVolume = seg.GetLabelVolumeNode()
#create a temporary model hierarchy for generating models
tempMH = slicer.vtkMRMLModelHierarchyNode()
slicer.mrmlScene.AddNode(tempMH)
if (labelVolume is not None) & (tempMH is not None):
parameters = {'InputVolume': labelVolume.GetID(), 'ColorTable': colorTable.GetID(),
'ModelSceneFile': tempMH.GetID(), 'GenerateAll': False, 'StartLabel': finding.GetColorID(),
'EndLabel': finding.GetColorID(), 'Name': labelVolume.GetName() + "_" + finding.GetName() + "_M"}
cliModelMaker = None
cliModelMaker = slicer.cli.run(slicer.modules.modelmaker, cliModelMaker, parameters, wait_for_completion = True)
genModelNodes = vtk.vtkCollection()
tempMH.GetChildrenModelNodes(genModelNodes)
if genModelNodes.GetNumberOfItems() > 0:
modelNode = genModelNodes.GetItemAsObject(0)
if modelNode:
if modelNode.IsA('vtkMRMLModelNode'):
hnode = slicer.vtkMRMLHierarchyNode.GetAssociatedHierarchyNode(modelNode.GetScene(), modelNode.GetID())
if hnode:
if seg.GetModelHierarchyNode():
SlicerLongitudinalPETCTModuleViewHelper.removeModelHierarchyAndChildModelNodesFromScene(seg.GetModelHierarchyNode())
hnode.SetName(seg.GetName()+"_Model")
seg.SetAndObserveModelHierarchyNodeID(hnode.GetID())
modelNode.SetName(labelVolume.GetName() + "_" + finding.GetName()+"_M")
if modelNode.GetDisplayNode():
modelNode.GetDisplayNode().SetName(labelVolume.GetName() + "_" + finding.GetName()+"_D")
modelNode.GetDisplayNode().AddViewNodeID(SlicerLongitudinalPETCTModuleViewHelper.getStandardViewNode().GetID())
hnode.SetName(labelVolume.GetName() + "_" + finding.GetName()+"_H")
modelNode.SetHideFromEditors(False)
else:
seg.SetAndObserveModelHierarchyNodeID("")
slicer.mrmlScene.RemoveNode(modelNode)
slicer.mrmlScene.RemoveNode(hnode)
slicer.mrmlScene.RemoveNode(tempMH.GetDisplayNode())
slicer.mrmlScene.RemoveNode(tempMH)
#return '#%02X%02X%02X' % (r,g,b)
开发者ID:QIICR,项目名称:LongitudinalPETCT,代码行数:50,代码来源:SlicerLongitudinalPETCTModuleViewHelper.py
示例15: widgetVisibleOnSlice
def widgetVisibleOnSlice(self, fidNode, sliceNodeID):
lm = slicer.app.layoutManager()
sliceNames = lm.sliceViewNames()
for sliceName in sliceNames:
sliceWidget = lm.sliceWidget(sliceName)
sliceView = sliceWidget.sliceView()
ms = vtk.vtkCollection()
sliceView.getDisplayableManagers(ms)
for i in range(ms.GetNumberOfItems()):
m = ms.GetItemAsObject(i)
if m.GetClassName() == 'vtkMRMLMarkupsFiducialDisplayableManager2D' and m.GetMRMLSliceNode().GetID() == sliceNodeID:
h = m.GetHelper()
seedWidget = h.GetWidget(fidNode)
return seedWidget.GetEnabled()
return 0
开发者ID:sankhesh,项目名称:Slicer,代码行数:15,代码来源:MarkupsInViewsSelfTest.py
示例16: execute
def execute(self):
output_collection = vtk.vtkCollection()
cluster=ClusterParticles(input,output_collection,feature_extractor=self.feature_extractor)
cluster._number_of_clusters=2
#cluster._method='MiniBatchKMeans'
cluster._method='KMeans'
cluster.execute()
points = vtk_to_numpy(input.GetPoints().GetData())
p_centroids = np.zeros([2,3])
for ii,ll in enumerate(cluster._unique_labels):
p_centroids[ii,:]=np.mean(points[cluster._labels==ll,:],axis=0)
if p_centroids[0,0] > p_centroids[1,0]:
self.cluster_tags=['left','right']
chest_region=[3,2]
chest_type=[3,3]
else:
self.cluster_tags=['right','left']
chest_region=[2,3]
chest_type=[3,3]
append=vtk.vtkAppendPolyData()
for k,tag,cr,ct in zip([0,1],self.cluster_tags,chest_region,chest_type):
self._out_vtk[tag]=output_collection.GetItemAsObject(k)
chest_region_arr = vtk.vtkUnsignedCharArray()
chest_region_arr.SetName('ChestRegion')
chest_type_arr = vtk.vtkUnsignedCharArray()
chest_type_arr.SetName('ChestType')
n_p = self._out_vtk[tag].GetNumberOfPoints()
chest_region_arr.SetNumberOfTuples(n_p)
chest_type_arr.SetNumberOfTuples(n_p)
for ii in xrange(self._out_vtk[tag].GetNumberOfPoints()):
chest_region_arr.SetValue(ii,cr)
chest_type_arr.SetValue(ii,ct)
self._out_vtk[tag].GetPointData().AddArray(chest_region_arr)
self._out_vtk[tag].GetPointData().AddArray(chest_type_arr)
append.AddInput(self._out_vtk[tag])
append.Update()
self._out_vtk['all']=append.GetOutput()
return self._out_vtk
开发者ID:151706061,项目名称:ChestImagingPlatform,代码行数:45,代码来源:cluster_particles.py
示例17: iniVTK
def iniVTK(self):
self.last_added_sphere_ren1 = None
self.newed_spheres = vtk.vtkCollection()
self.sphere_radius_ren1 = 2.0
self.bouttons_spheres = []
self.slice_assembly = None
self.image_roi = None
self.im_importer = vtk.vtkImageImport()
self.sphere = vtk.vtkSphereSource()
self.sphere.SetRadius(2.0)
self.sphere_mapper = vtk.vtkPolyDataMapper()
self.sphere_mapper.SetInputConnection(self.sphere.GetOutputPort())
self.sphere_actor_ren2 = vtk.vtkActor()
self.sphere.SetCenter(show_height / 2, show_width / 2, 0)
self.sphere_actor_ren2.SetMapper(self.sphere_mapper)
self.sphere_actor_ren2.GetProperty().SetColor(255.0, 0, 0)
self.vtk_widget.GetRenderWindow().SetSize(800, 400)
self.image_actor = vtk.vtkImageActor()
self.ren1 = vtk.vtkRenderer()
self.ren2 = vtk.vtkRenderer()
self.interactorStyle = BouttonInteractorStyle()
self.vtk_widget.SetInteractorStyle(self.interactorStyle)
self.vtk_widget.GetRenderWindow().AddRenderer(self.ren1)
self.vtk_widget.GetRenderWindow().AddRenderer(self.ren2)
self.ren1.SetViewport(0.0, 0.0, 0.5, 1.0)
self.ren2.SetViewport(0.5, 0.0, 1.0, 1.0)
self.ren2.AddActor(self.sphere_actor_ren2)
self.imageLevelFilter = vtk.vtkImageMapToWindowLevelColors()
self.imageLevelFilter.SetLevel(400)
self.imageLevelFilter.SetWindow(800)
self.im_importer.SetNumberOfScalarComponents(1)
self.im_importer.SetDataScalarTypeToUnsignedShort()
self.im_importer.SetDataExtent(0, show_width - 1, 0, show_height - 1, 0, 0)
self.im_importer.SetWholeExtent(0, show_width - 1, 0, show_height - 1, 0, 0)
self.imageLevelFilter.SetInputConnection(self.im_importer.GetOutputPort())
self.image_actor.SetInput(self.imageLevelFilter.GetOutput())
self.ren1_sphere_actors = vtk.vtkActorCollection()
self.pointPicker = vtk.vtkPointPicker()
self.actorPicker = vtk.vtkPropPicker()
self.pickedActor = None
self.ren1.AddActor(self.image_actor)
self.ren2.AddActor(self.image_actor)
开发者ID:sulei1324,项目名称:lab_codes,代码行数:42,代码来源:test1.py
示例18: IgnoreIrrelevantMetrics
def IgnoreIrrelevantMetrics( metricDict, peNode ):
if ( peNode is None or PythonMetricsCalculatorLogic.GetPerkEvaluatorLogic() is None ):
return
irrelevantTransformMetrics = []
relevantTransformNodes = vtk.vtkCollection()
PythonMetricsCalculatorLogic.GetPerkEvaluatorLogic().GetProxyRelevantTransformNodes( peNode.GetTrackedSequenceBrowserNode(), relevantTransformNodes )
for metricInstanceID in metricDict:
metricTransformRoles = PythonMetricsCalculatorLogic.GetTransformRoles( metricDict[ metricInstanceID ] )
metricInstanceNode = PythonMetricsCalculatorLogic.GetMRMLScene().GetNodeByID( metricInstanceID )
for role in metricTransformRoles:
transformNode = metricInstanceNode.GetRoleNode( role, metricInstanceNode.TransformRole )
transformNodeRelevant = relevantTransformNodes.IsItemPresent( transformNode )
if ( not transformNodeRelevant ):
irrelevantTransformMetrics.append( metricInstanceID )
for metricInstanceID in irrelevantTransformMetrics:
metricDict.pop( metricInstanceID )
开发者ID:mholden8,项目名称:PerkTutor,代码行数:21,代码来源:PythonMetricsCalculator.py
示例19: __init__
def __init__( self ):
self.realTimeMetrics = dict()
self.realTimeMetricsTable = None
self.realTimeProxyNodeCollection = vtk.vtkCollection()
开发者ID:mholden8,项目名称:PerkTutor,代码行数:4,代码来源:PythonMetricsCalculator.py
示例20: load
def load(self,loadable):
""" Load the DICOM SEG object
"""
print('DICOM SEG load()')
labelNodes = vtk.vtkCollection()
uid = None
try:
uid = loadable.uid
print ('in load(): uid = ', uid)
except AttributeError:
return False
res = False
# make the output directory
outputDir = os.path.join(slicer.app.temporaryPath,"QIICR","SEG",loadable.uid)
try:
os.makedirs(outputDir)
except:
pass
# produces output label map files, one per segment, and information files with
# the terminology information for each segment
segFileName = slicer.dicomDatabase.fileForInstance(uid)
if segFileName is None:
print 'Failed to get the filename from the DICOM database for ', uid
return False
parameters = {
"inputSEGFileName": segFileName,
"outputDirName": outputDir,
}
seg2nrrd = None
try:
seg2nrrd = slicer.modules.seg2nrrd
except AttributeError:
print 'Unable to find CLI module SEG2NRRD, unable to load DICOM Segmentation object'
return False
cliNode = None
cliNode = slicer.cli.run(seg2nrrd, cliNode, parameters, wait_for_completion=True)
if cliNode.GetStatusString() != 'Completed':
print 'SEG2NRRD did not complete successfully, unable to load DICOM Segmentation'
return False
# create a new color node to be set up with the colors in these segments
colorLogic = slicer.modules.colors.logic()
segmentationColorNode = slicer.vtkMRMLColorTableNode()
segmentationColorNode.SetName(loadable.name)
segmentationColorNode.SetTypeToUser();
segmentationColorNode.SetHideFromEditors(0)
segmentationColorNode.SetAttribute("Category", "File")
segmentationColorNode.NamesInitialisedOff()
slicer.mrmlScene.AddNode(segmentationColorNode)
# also create a new terminology and associate it with this color node
colorLogic.CreateNewTerminology(segmentationColorNode.GetName())
import glob
numberOfSegments = len(glob.glob(os.path.join(outputDir,'*.nrrd')))
# resize the color table to include the segments plus 0 for the background
print ('number of segments = ',numberOfSegments)
segmentationColorNode.SetNumberOfColors(numberOfSegments + 1)
segmentationColorNode.SetColor(0, 'background', 0.0, 0.0, 0.0, 0.0)
seriesName = self.referencedSeriesName(loadable)
segmentNodes = []
for segmentId in range(numberOfSegments):
# load each of the segments' segmentations
# Initialize color and terminology from .info file
# See SEG2NRRD.cxx and EncodeSEG.cxx for how it's written.
# Format of the .info file (no leading spaces, labelNum, RGBColor, SegmentedPropertyCategory and
# SegmentedPropertyCategory are required):
# labelNum;RGB:R,G,B;SegmentedPropertyCategory:code,scheme,meaning;SegmentedPropertyType:code,scheme,meaning;SegmentedPropertyTypeModifier:code,scheme,meaning;AnatomicRegion:code,scheme,meaning;AnatomicRegionModifier:code,scheme,meaning
# R, G, B are 0-255 in file, but mapped to 0-1 for use in color node
# set defaults in case of missing fields, modifiers are optional
rgb = (0., 0., 0.)
colorIndex = segmentId + 1
categoryCode = 'T-D0050'
categoryCodingScheme = 'SRT'
categoryCodeMeaning = 'Tissue'
typeCode = 'T-D0050'
typeCodeMeaning = 'Tissue'
typeCodingScheme = 'SRT'
typeModCode = ''
typeModCodingScheme = ''
typeModCodeMeaning = ''
regionCode = 'T-D0010'
regionCodingScheme = 'SRT'
regionCodeMeaning = 'Entire Body'
regionModCode = ''
regionModCodingScheme = ''
regionModCodeMeaning = ''
infoFileName = os.path.join(outputDir,str(segmentId+1)+".info")
print ('Parsing info file', infoFileName)
with open(infoFileName, 'r') as infoFile:
for line in infoFile:
line = line.rstrip()
#.........这里部分代码省略.........
开发者ID:Sunderlandkyl,项目名称:Reporting,代码行数:101,代码来源:DICOMSegmentationPlugin.py
注:本文中的vtk.vtkCollection函数示例由纯净天空整理自Github/MSDocs等源码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。 |
请发表评论