How to set ImageItem colormaps in code

瀏覽次數:6,034 次
跳到第一則未讀訊息

Alex A

未讀,
2013年9月18日 下午4:43:382013/9/18
收件者:pyqt...@googlegroups.com
Hello,
   I'm just starting with pyqtgraph, and somewhat new to Python overall, so apologies if this is something that is addressed somewhere else but I haven't been able to find it.   I'm trying to figure out how to set the colormap for an ImageItem in code rather than via the GradientEditor or other GUI methods. 
   For a trivial example, starting with the ImageItem.py example code I'd like to make it be just a gradient along the red intensity for values 0 to 0.5, then ramp the green from 0.5 to 1.0.  i.e.:
val -> R,G,B
0.0 -> 0,0,0
0.5 -> 255,0,0
1.0 -> 255,255,0

   It seems that the setLookupTable() is the function that should be used, but I can't seem to figure out exactly how to use it.   Could someone post what I'd need to add to the ImageItem.py example to accomplish this?

  Thanks

Luke Campagnola

未讀,
2013年9月18日 晚上9:57:292013/9/18
收件者:pyqt...@googlegroups.com
Like this:

import numpy as np
import pyqtgraph as pg

# build lookup table
lut = np.zeros((256,3), dtype=np.ubyte)
lut[:128,0] = np.arange(0,255,2)
lut[128:,0] = 255
lut[:,1] = np.arange(255)

# random image data
img = np.random.normal(size=(100,100))

# GUI
win = pg.GraphicsWindow()
view = win.addViewBox()
view.setAspectLocked(True)
item = pg.ImageItem(img)
view.addItem(item)
item.setLookupTable(lut)
item.setLevels([0,1])

Equivalently, you could use a ColorMap to generate the lookup table:

pos = np.array([0.0, 0.5, 1.0])
color = np.array([[0,0,0,255], [255,128,0,255], [255,255,0,255]], dtype=np.ubyte)
map = pg.ColorMap(pos, color)
lut = map.getLookupTable(0.0, 1.0, 256)



Luke

Alex A

未讀,
2013年9月19日 下午3:47:582013/9/19
收件者:pyqt...@googlegroups.com
Luke,
   Thanks, that got me most of what I needed and I figured out some more on my own.   I case it's helpful for anyone else just starting out, below is what I modified the central part of the ImageItem.py example into for testing out the colormaps.  I realize it's a bit hacked, but it was just to test whether I understood some things.
   I was having some issues understanding how some of the parameters related to each other as well as when to call certain things.   In particular I was having a hard time at first figuring out why my color scale (i.e. the color of the background gradient in my example) kept changing as I added the solid bars before I realized I had to call setLevels() inside the updateData(). 

   Thanks again for the help,
          Alex


## Set initial view bounds
view.setRange(QtCore.QRectF(0, 0, 600, 600))

#create test pattern background, basically a gradient from left to right
gradCen=1000  #midpoint of gradient
data=np.zeros([15, 600, 600], dtype=np.uint16)
for i in range(data.shape[1]):
    data[:,i,:] = gradCen-(data.shape[1]/2)+i    
#add horizontal bars, the same color as the extremes of the gradient
data[5:10,:,200:210] = gradCen-300
data[5:10,:,300:310] = gradCen+300
#add horizontal bars, the color that should be the extremes of the colorscale
data[10:15,:,200:210] = 0
data[10:15,:,300:310] = gradCen*2


#create a color map that goes from full red, to yellow, then to full green
pos = np.array([0.0, 0.5, 1.0])  #absolute scale here relative to the expected data not important I believe
color = np.array([[255,0,0,255], [255,255,0,255], [0,255,0,255]], dtype=np.ubyte)
colmap = pg.ColorMap(pos, color)

#get LUT, first first two params should match the position scale extremes passed to ColorMap(). 
# I believe last one just has to be >= the difference between the min and max level set later
lut = colmap.getLookupTable(0, 1.0, 2000)

img.setLookupTable(lut)
#img.setLevels([0,2048])   #don't do here, it needs to be after each setImage to work properly


updateTime = ptime.time()
fps = 0
i = 0
def updateData():
    global img, data, i, updateTime, fps

    ## Display the data
    img.setImage(data[i])
    #set the levels to the min and max we desire on our scale
    img.setLevels([0,2000]) 
   
    i = (i+1) % data.shape[0]

    QtCore.QTimer.singleShot(200, updateData)
    now = ptime.time()
    fps2 = 1.0 / (now-updateTime)
    updateTime = now
    fps = fps * 0.9 + fps2 * 0.1
   
    #print "%0.1f fps" % fps

Federico Barabas

未讀,
2015年1月29日 中午12:12:282015/1/29
收件者:pyqt...@googlegroups.com
Is there a way to convert matplotlib colormaps to use them with pyqtgraph?

I'm specially interested in cubehelix:  matplotlib._cm.cubehelix

dyadkin

未讀,
2015年4月30日 上午8:57:012015/4/30
收件者:pyqt...@googlegroups.com
Here it is:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import numpy as np


# taken from https://www.mrao.cam.ac.uk/~dag/CUBEHELIX/cubehelix.py
lut_cubehelix = np.array((
(0.00000, 0.00000, 0.00000),
(2.04510, 0.34680, 1.68810),
(4.02390, 0.71145, 3.45015),
(5.93385, 1.10160, 5.28360),
(7.76730, 1.51470, 7.18335),
(9.52935, 1.95585, 9.14685),
(11.20980, 2.42505, 11.16645),
(12.80865, 2.92485, 13.23960),
(14.32590, 3.46035, 15.36120),
(15.75645, 4.02900, 17.52615),
(17.10030, 4.63590, 19.73190),
(18.35490, 5.27850, 21.97080),
(19.52025, 5.96445, 24.23775),
(20.59635, 6.68865, 26.53020),
(21.57810, 7.45875, 28.84305),
(22.47060, 8.26965, 31.16865),
(23.26875, 9.12900, 33.50445),
(23.97510, 10.03170, 35.84280),
(24.59220, 10.98030, 38.18115),
(25.11750, 11.97735, 40.51185),
(25.55100, 13.02030, 42.83235),
(25.89780, 14.11425, 45.13755),
(26.15535, 15.25410, 47.41980),
(26.32620, 16.44240, 49.67655),
(26.41545, 17.67915, 51.90270),
(26.42055, 18.96180, 54.09060),
(26.34660, 20.29545, 56.24025),
(26.19615, 21.67500, 58.34655),
(25.96920, 23.10045, 60.40185),
(25.67085, 24.57180, 62.40360),
(25.30620, 26.08905, 64.34670),
(24.87525, 27.65220, 66.22860),
(24.38055, 29.25615, 68.04675),
(23.82975, 30.90090, 69.79350),
(23.22540, 32.58900, 71.46885),
(22.57005, 34.31535, 73.07025),
(21.86880, 36.07995, 74.59005),
(21.12420, 37.88025, 76.02825),
(20.34390, 39.71370, 77.38485),
(19.53045, 41.58030, 78.65220),
(18.68895, 43.47750, 79.83030),
(17.82195, 45.40530, 80.91660),
(16.93710, 47.35860, 81.91110),
(16.03695, 49.33485, 82.81125),
(15.12915, 51.33660, 83.61450),
(14.21625, 53.35620, 84.32085),
(13.30335, 55.39365, 84.93030),
(12.39555, 57.44640, 85.44030),
(11.50050, 59.51190, 85.85085),
(10.61820, 61.58760, 86.16450),
(9.75630, 63.67095, 86.37615),
(8.92245, 65.75940, 86.49090),
(8.11665, 67.85040, 86.50620),
(7.34655, 69.94140, 86.42460),
(6.61470, 72.03240, 86.24865),
(5.92875, 74.11575, 85.97580),
(5.29380, 76.19145, 85.60860),
(4.70985, 78.25695, 85.15215),
(4.18455, 80.31225, 84.60390),
(3.72300, 82.34970, 83.96895),
(3.32775, 84.36930, 83.24985),
(3.00135, 86.36595, 82.44660),
(2.75145, 88.34220, 81.56430),
(2.58060, 90.29295, 80.60550),
(2.49135, 92.21565, 79.57275),
(2.48625, 94.10520, 78.46860),
(2.57040, 95.96415, 77.30070),
(2.74890, 97.78995, 76.06650),
(3.01920, 99.57495, 74.77620),
(3.38895, 101.32425, 73.42980),
(3.85815, 103.03020, 72.03240),
(4.43190, 104.69280, 70.58910),
(5.10765, 106.30950, 69.10500),
(5.89050, 107.88030, 67.58265),
(6.78300, 109.40265, 66.02715),
(7.78260, 110.87655, 64.44360),
(8.89440, 112.29690, 62.83710),
(10.11840, 113.66370, 61.21275),
(11.45205, 114.97695, 59.57310),
(12.90300, 116.23410, 57.92835),
(14.46360, 117.43260, 56.27850),
(16.13895, 118.57755, 54.63120),
(17.92650, 119.66130, 52.99155),
(19.82880, 120.68640, 51.36465),
(21.84075, 121.65285, 49.75305),
(23.96490, 122.55810, 48.16695),
(26.19870, 123.40470, 46.60635),
(28.54215, 124.18755, 45.07890),
(30.99015, 124.91175, 43.58970),
(33.54525, 125.57475, 42.14385),
(36.20235, 126.17400, 40.74390),
(38.96145, 126.71715, 39.39750),
(41.81745, 127.19655, 38.10720),
(44.76780, 127.61985, 36.88065),
(47.81250, 127.98195, 35.72040),
(50.94645, 128.28795, 34.62900),
(54.16710, 128.53530, 33.61410),
(57.46935, 128.72655, 32.67825),
(60.85320, 128.86170, 31.82400),
(64.30845, 128.94330, 31.05900),
(67.83765, 128.97390, 30.38325),
(71.43315, 128.95095, 29.80185),
(75.09240, 128.87955, 29.31735),
(78.80775, 128.76225, 28.93485),
(82.57920, 128.59650, 28.65690),
(86.39655, 128.38740, 28.48350),
(90.25980, 128.13495, 28.42230),
(94.16385, 127.84425, 28.46820),
(98.10105, 127.51275, 28.63140),
(102.06885, 127.14810, 28.90935),
(106.05960, 126.74775, 29.30205),
(110.07075, 126.31680, 29.81460),
(114.09465, 125.85525, 30.44955),
(118.12620, 125.37075, 31.20435),
(122.16285, 124.85820, 32.07900),
(126.19695, 124.32780, 33.07605),
(130.22340, 123.77700, 34.19805),
(134.23710, 123.21090, 35.44245),
(138.23295, 122.62950, 36.80670),
(142.20585, 122.04045, 38.29590),
(146.15070, 121.44120, 39.90495),
(150.06240, 120.83685, 41.63640),
(153.93585, 120.22995, 43.48770),
(157.76340, 119.62560, 45.45630),
(161.54250, 119.02380, 47.53965),
(165.27060, 118.42710, 49.74030),
(168.93750, 117.84060, 52.05315),
(172.54320, 117.26430, 54.47565),
(176.08005, 116.70330, 57.00780),
(179.54550, 116.15760, 59.64450),
(182.93700, 115.63230, 62.38320),
(186.24435, 115.12995, 65.22390),
(189.47010, 114.65310, 68.15895),
(192.60660, 114.20175, 71.18580),
(195.65385, 113.78100, 74.30445),
(198.60420, 113.39340, 77.50725),
(201.45510, 113.04150, 80.79165),
(204.20655, 112.72530, 84.15510),
(206.85090, 112.44735, 87.58995),
(209.39070, 112.21275, 91.09365),
(211.82085, 112.02150, 94.66365),
(214.13880, 111.87615, 98.29230),
(216.34455, 111.77670, 101.97450),
(218.43300, 111.72570, 105.70770),
(220.40670, 111.72570, 109.48680),
(222.26055, 111.77925, 113.30415),
(223.99455, 111.88635, 117.15975),
(225.60870, 112.04955, 121.04340),
(227.10045, 112.26885, 124.95255),
(228.47235, 112.54680, 128.87955),
(229.72440, 112.88085, 132.82185),
(230.85150, 113.27610, 136.77435),
(231.86130, 113.73255, 140.72940),
(232.74870, 114.24765, 144.68445),
(233.51625, 114.82650, 148.63185),
(234.16395, 115.46655, 152.56650),
(234.69690, 116.17035, 156.48585),
(235.11255, 116.93535, 160.38225),
(235.41345, 117.76410, 164.25060),
(235.60215, 118.65405, 168.08580),
(235.68120, 119.60775, 171.88530),
(235.65315, 120.62265, 175.64400),
(235.51800, 121.69875, 179.35425),
(235.28340, 122.83605, 183.01350),
(234.94680, 124.03455, 186.61665),
(234.51585, 125.29425, 190.16115),
(233.99055, 126.61005, 193.63935),
(233.37600, 127.98450, 197.05125),
(232.67730, 129.41505, 200.38920),
(231.89445, 130.90170, 203.65065),
(231.03510, 132.44190, 206.83305),
(230.10180, 134.03310, 209.93130),
(229.09965, 135.67785, 212.94540),
(228.03120, 137.37105, 215.86770),
(226.90155, 139.11015, 218.70075),
(225.71835, 140.89515, 221.43690),
(224.48160, 142.72350, 224.07615),
(223.20150, 144.59520, 226.61595),
(221.87805, 146.50515, 229.05375),
(220.51635, 148.45335, 231.38955),
(219.12660, 150.43470, 233.61825),
(217.70880, 152.45175, 235.74240),
(216.26805, 154.49685, 237.76200),
(214.81200, 156.57255, 239.66940),
(213.34575, 158.67120, 241.47225),
(211.87185, 160.79280, 243.16290),
(210.39540, 162.93735, 244.74645),
(208.92660, 165.09720, 246.22290),
(207.46290, 167.27235, 247.58715),
(206.01705, 169.46280, 248.84685),
(204.58650, 171.66090, 249.99690),
(203.18145, 173.86920, 251.04240),
(201.80445, 176.08005, 251.98335),
(200.46060, 178.29345, 252.82230),
(199.15500, 180.50430, 253.55925),
(197.89020, 182.71515, 254.19420),
(196.67385, 184.91835, 254.73480),
(195.50595, 187.11390, 255.00000),
(194.39415, 189.29925, 255.00000),
(193.34100, 191.47185, 255.00000),
(192.34905, 193.62660, 255.00000),
(191.42595, 195.76605, 255.00000),
(190.56915, 197.88255, 255.00000),
(189.78885, 199.97610, 255.00000),
(189.08250, 202.04670, 255.00000),
(188.45265, 204.08925, 255.00000),
(187.90695, 206.10120, 255.00000),
(187.44540, 208.08255, 255.00000),
(187.06800, 210.03075, 254.69145),
(186.77985, 211.94580, 254.25285),
(186.58095, 213.82260, 253.76580),
(186.47385, 215.66115, 253.23795),
(186.46110, 217.45890, 252.66930),
(186.54015, 219.21840, 252.06750),
(186.71610, 220.93200, 251.43765),
(186.98385, 222.60480, 250.78485),
(187.35105, 224.22915, 250.11165),
(187.81260, 225.81015, 249.42315),
(188.36850, 227.34525, 248.72700),
(189.02130, 228.83190, 248.02575),
(189.76845, 230.27010, 247.32705),
(190.60995, 231.65985, 246.63090),
(191.54325, 233.00115, 245.94750),
(192.57090, 234.29400, 245.27940),
(193.68525, 235.53585, 244.63170),
(194.88885, 236.72925, 244.00695),
(196.17915, 237.87420, 243.41535),
(197.55105, 238.97325, 242.85435),
(199.00710, 240.02130, 242.33415),
(200.53965, 241.02090, 241.85730),
(202.14870, 241.97460, 241.42635),
(203.82915, 242.88495, 241.04640),
(205.57845, 243.74685, 240.72510),
(207.39660, 244.56540, 240.45990),
(209.27340, 245.34315, 240.26100),
(211.20885, 246.07755, 240.12585),
(213.20040, 246.77115, 240.06210),
(215.24040, 247.42650, 240.06975),
(217.32375, 248.04615, 240.15645),
(219.45045, 248.63010, 240.31965),
(221.61285, 249.18090, 240.56445),
(223.80840, 249.70110, 240.89340),
(226.02945, 250.19325, 241.30905),
(228.27090, 250.65480, 241.81140),
(230.53020, 251.09340, 242.40300),
(232.80225, 251.51160, 243.08385),
(235.07940, 251.90685, 243.85650),
(237.35655, 252.28680, 244.72350),
(239.63115, 252.64890, 245.68230),
(241.89810, 253.00080, 246.73545),
(244.14975, 253.34250, 247.88295),
(246.37845, 253.67655, 249.12225),
(248.58420, 254.00805, 250.45335),
(250.76190, 254.33700, 251.87880),
(252.90135, 254.66595, 253.39350),
(255.00000, 255.00000, 255.00000)),
dtype=np.ubyte
)

Federico Barabas

未讀,
2015年5月2日 晚上10:43:232015/5/2
收件者:pyqt...@googlegroups.com
thanks a lot!

--
You received this message because you are subscribed to a topic in the Google Groups "pyqtgraph" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/pyqtgraph/gEjC08Vb8NQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to pyqtgraph+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/pyqtgraph/3f2fbe52-000d-43c2-8318-b66d435c2281%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Federico Barabas

未讀,
2015年5月13日 下午1:08:482015/5/13
收件者:pyqt...@googlegroups.com
For some reason it's not really working. Here's what I'm trying:

self.img = pg.ImageItem()

self.vb.addItem(self.img)

self.hist = pg.HistogramLUTItem()

self.hist.setImageItem(self.img)

self.img.setLookupTable(cubehelix())


where cubehelix is just a function that returns the lut_cubehelix array


what am I doing wrong?

dyadkin

未讀,
2015年5月15日 上午11:27:422015/5/15
收件者:pyqt...@googlegroups.com
I do not really know. I use ImageView widget and it works fine, I just had to subclass, otherwise if you resize the window, LUT drops to the default one. Now it works fine.

class ImageView(pg.ImageView):
def __init__(self, *args, **kwargs):
super(ImageView, self).__init__(*args, **kwargs)
self.lut = None

def updateImage(self, autoHistogramRange=True):
super(ImageView, self).updateImage(autoHistogramRange)
self.getImageItem().setLookupTable(self.lut)

def setLookupTable(self, lut):
self.lut = lut
self.updateImage()

def resizeEvent(self, event):
super(ImageView, self).resizeEvent(event)
self.updateImage()

Thus, just:
iv = ImageView()
iv.setLookupTable(cubehelix()) 
should work.

dyadkin

未讀,
2015年5月15日 下午3:33:202015/5/15
收件者:pyqt...@googlegroups.com
Finally, I have written a generator of lookup table for pyqtgraph.
Cubehelix:

def cubehelix(gamma=1.0, s=0.5, r=-1.5, h=1.0):
def get_color_function(p0, p1):
def color(x):
xg = x ** gamma
a = h * xg * (1 - xg) / 2
phi = 2 * np.pi * (s / 3 + r * x)
return xg + a * (p0 * np.cos(phi) + p1 * np.sin(phi))
return color

array = np.empty((256, 3))
abytes = np.arange(0, 1, 1/256.)
array[:, 0] = get_color_function(-0.14861, 1.78277)(abytes) * 255
array[:, 1] = get_color_function(-0.29227, -0.90649)(abytes) * 255
array[:, 2] = get_color_function(1.97294, 0.0)(abytes) * 255
return array

Rainbow:

def rainbow():
array = np.empty((256, 3))
abytes = np.arange(0, 1, 0.00390625)
array[:, 0] = np.abs(2 * abytes - 0.5) * 255
array[:, 1] = np.sin(abytes * np.pi) * 255
array[:, 2] = np.cos(abytes * np.pi / 2) * 255
return array

Federico Barabas

未讀,
2015年5月17日 中午12:54:362015/5/17
收件者:pyqt...@googlegroups.com
Awesome!
I didn't want to use an ImageView, so in the update routine I did this:

self.img.setImage(image, autoLevels=False, lut=self.lut)


where self.lut points to the cubehelix


--
You received this message because you are subscribed to a topic in the Google Groups "pyqtgraph" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/pyqtgraph/gEjC08Vb8NQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to pyqtgraph+...@googlegroups.com.

Federico Barabas

未讀,
2015年5月17日 下午1:04:472015/5/17
收件者:pyqt...@googlegroups.com
The only (small) thing that bugs me is the fact that the gradient in the HistogramLutItem doesn't reflect the cubehelix gradient

Luke Campagnola

未讀,
2015年5月18日 晚上11:01:182015/5/18
收件者:pyqt...@googlegroups.com
If you are using ImageView, then you can assign a colormap to the gradient editor rather than the image:

    imageview.ui.histogram.gradient.setColorMap(colormap)

This should also make it unnecessary to deal with the widget resize resetting the LUT. 

You received this message because you are subscribed to the Google Groups "pyqtgraph" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pyqtgraph+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/pyqtgraph/CAFGKJ92gPN4-%2Br11HvDx6TUnPJyv7tg5kRFWFUi3nat4KkK-9Q%40mail.gmail.com.

Federico Barabas

未讀,
2015年5月19日 上午10:37:262015/5/19
收件者:pyqt...@googlegroups.com
ok, but I think that's not so easy because the cubehelix lut has a continous change in color, so I can't think of a way of creating a colormap with positions

Federico Barabas

未讀,
2016年7月11日 晚上7:23:212016/7/11
收件者:pyqtgraph
I went over this thing again and I managed to change the gradient to the cubehelix colormap in this way:

I got the cubehelix RGB array from https://www.mrao.cam.ac.uk/~dag/CUBEHELIX/cubehelix.py. And then these lines made the trick:

        hist = pyqtgraph.HistogramLUTItem()
        cubehelix = cubehelix().astype(int)
        pos, color = np.arange(0, 1, 1/256), cubehelix
        hist.gradient.setColorMap(pyqtgraph.ColorMap(pos, color))

One question remains: is there an easy way of hiding all the ticks next to the gradient? I don't need them and they don't look good because the colormap has a tick for each position between 0 and 255. I tried subclassing TickSliderItem but in the end I failed.


To unsubscribe from this group and all its topics, send an email to pyqtgraph+unsubscribe@googlegroups.com.


--
You received this message because you are subscribed to the Google Groups "pyqtgraph" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pyqtgraph+unsubscribe@googlegroups.com.

--
You received this message because you are subscribed to a topic in the Google Groups "pyqtgraph" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/pyqtgraph/gEjC08Vb8NQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to pyqtgraph+unsubscribe@googlegroups.com.

Luke Campagnola

未讀,
2016年7月12日 凌晨2:08:422016/7/12
收件者:pyqt...@googlegroups.com
I would love it if we could move away from using lookup tables and toward a more general colormapping model. The ColorMap class was intended to be a start in this direction, but I think this would take a lot more work to sort out.


On Mon, Jul 11, 2016 at 4:23 PM, Federico Barabas <fede.b...@gmail.com> wrote:

One question remains: is there an easy way of hiding all the ticks next to the gradient? I don't need them and they don't look good because the colormap has a tick for each position between 0 and 255. I tried subclassing TickSliderItem but in the end I failed.

I suppose the easiest way is just to hide the ticks after you set the gradient, and maybe adjust the width of the gradient editor, like:

  for tick in histogramLutItem.gradient.ticks:
      tick.hide()
  histogramLutItem.gradient.setFixedWidth(...)

Federico Barabas

未讀,
2016年7月12日 上午9:25:102016/7/12
收件者:pyqt...@googlegroups.com
Thank you Luke! I'm sorry I missed that simple hide command

--
You received this message because you are subscribed to a topic in the Google Groups "pyqtgraph" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/pyqtgraph/gEjC08Vb8NQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to pyqtgraph+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/pyqtgraph/CACZXET8sUPK1OgprTcDC%2BS_Fhxd%2B7TRu7%3DUYt2oEH9SRaseeCA%40mail.gmail.com.
回覆所有人
回覆作者
轉寄
0 則新訊息