OpenCV3.1.0中调用MHI(Motion History Images, 运动历史图像)

写在前边:

OpenCV3.0+要想使用MHI,就要现安装扩展模块opencv_contrib。安装方法见:ubuntu 14.04 64位 安装Opencv3.1.0 (包含opencv_contrib模块)

 

OpenCV2.4.11中samples/python2/motempl.py 就是使用mhi的一个例子,但是在OpenCV3.1.0下使用的话需要稍加修改:

1.把OpenCV2.4.11/samples/python2/motempl.py 复制到OpenCV3.1.0/samples/python 目录下。

  OpenCV3.1.0的samples里边已经没有motempl.py了。 注:motempl.py需要使用common.py 和 video.py两个文件,直接使用3.1.0/samples里边的这两个文件就行。

 

2.把motempl.py 的 47、48、49、75这四行的代码,改为:

47 cv2.motempl.updateMotionHistory(motion_mask, motion_history, timestamp, MHI_DURATION)
48 mg_mask, mg_orient = cv2.motempl.calcMotionGradient(motion_history, MAX_TIME_DELTA, MIN_TIME_DELTA, apertureSize=5)
49 seg_mask, seg_bounds = cv2.motempl.segmentMotion(motion_history, timestamp, MAX_TIME_DELTA)

75 angle = cv2.motempl.calcGlobalOrientation(orient_roi, mask_roi, mhi_roi, timestamp, MHI_DURATION)

  其实就是在前边加了个“motempl.”,因为3.0+版本里,把这些函数放在了motempl API里边。

这里贴出来common.py video.py motempl.py三个文件的代码。

common.py

  1 #!/usr/bin/env python
  2 
  3 '''
  4 This module contains some common routines used by other samples.
  5 '''
  6 
  7 # Python 2/3 compatibility
  8 from __future__ import print_function
  9 import sys
 10 PY3 = sys.version_info[0] == 3
 11 
 12 if PY3:
 13     from functools import reduce
 14 
 15 import numpy as np
 16 import cv2
 17 
 18 # built-in modules
 19 import os
 20 import itertools as it
 21 from contextlib import contextmanager
 22 
 23 image_extensions = ['.bmp', '.jpg', '.jpeg', '.png', '.tif', '.tiff', '.pbm', '.pgm', '.ppm']
 24 
 25 class Bunch(object):
 26     def __init__(self, **kw):
 27         self.__dict__.update(kw)
 28     def __str__(self):
 29         return str(self.__dict__)
 30 
 31 def splitfn(fn):
 32     path, fn = os.path.split(fn)
 33     name, ext = os.path.splitext(fn)
 34     return path, name, ext
 35 
 36 def anorm2(a):
 37     return (a*a).sum(-1)
 38 def anorm(a):
 39     return np.sqrt( anorm2(a) )
 40 
 41 def homotrans(H, x, y):
 42     xs = H[0, 0]*x + H[0, 1]*y + H[0, 2]
 43     ys = H[1, 0]*x + H[1, 1]*y + H[1, 2]
 44     s  = H[2, 0]*x + H[2, 1]*y + H[2, 2]
 45     return xs/s, ys/s
 46 
 47 def to_rect(a):
 48     a = np.ravel(a)
 49     if len(a) == 2:
 50         a = (0, 0, a[0], a[1])
 51     return np.array(a, np.float64).reshape(2, 2)
 52 
 53 def rect2rect_mtx(src, dst):
 54     src, dst = to_rect(src), to_rect(dst)
 55     cx, cy = (dst[1] - dst[0]) / (src[1] - src[0])
 56     tx, ty = dst[0] - src[0] * (cx, cy)
 57     M = np.float64([[ cx,  0, tx],
 58                     [  0, cy, ty],
 59                     [  0,  0,  1]])
 60     return M
 61 
 62 
 63 def lookat(eye, target, up = (0, 0, 1)):
 64     fwd = np.asarray(target, np.float64) - eye
 65     fwd /= anorm(fwd)
 66     right = np.cross(fwd, up)
 67     right /= anorm(right)
 68     down = np.cross(fwd, right)
 69     R = np.float64([right, down, fwd])
 70     tvec = -np.dot(R, eye)
 71     return R, tvec
 72 
 73 def mtx2rvec(R):
 74     w, u, vt = cv2.SVDecomp(R - np.eye(3))
 75     p = vt[0] + u[:,0]*w[0]    # same as np.dot(R, vt[0])
 76     c = np.dot(vt[0], p)
 77     s = np.dot(vt[1], p)
 78     axis = np.cross(vt[0], vt[1])
 79     return axis * np.arctan2(s, c)
 80 
 81 def draw_str(dst, target, s):
 82     x, y = target
 83     cv2.putText(dst, s, (x+1, y+1), cv2.FONT_HERSHEY_PLAIN, 1.0, (0, 0, 0), thickness = 2, lineType=cv2.LINE_AA)
 84     cv2.putText(dst, s, (x, y), cv2.FONT_HERSHEY_PLAIN, 1.0, (255, 255, 255), lineType=cv2.LINE_AA)
 85 
 86 class Sketcher:
 87     def __init__(self, windowname, dests, colors_func):
 88         self.prev_pt = None
 89         self.windowname = windowname
 90         self.dests = dests
 91         self.colors_func = colors_func
 92         self.dirty = False
 93         self.show()
 94         cv2.setMouseCallback(self.windowname, self.on_mouse)
 95 
 96     def show(self):
 97         cv2.imshow(self.windowname, self.dests[0])
 98 
 99     def on_mouse(self, event, x, y, flags, param):
100         pt = (x, y)
101         if event == cv2.EVENT_LBUTTONDOWN:
102             self.prev_pt = pt
103         elif event == cv2.EVENT_LBUTTONUP:
104             self.prev_pt = None
105 
106         if self.prev_pt and flags & cv2.EVENT_FLAG_LBUTTON:
107             for dst, color in zip(self.dests, self.colors_func()):
108                 cv2.line(dst, self.prev_pt, pt, color, 5)
109             self.dirty = True
110             self.prev_pt = pt
111             self.show()
112 
113 
114 # palette data from matplotlib/_cm.py
115 _jet_data =   {'red':   ((0., 0, 0), (0.35, 0, 0), (0.66, 1, 1), (0.89,1, 1),
116                          (1, 0.5, 0.5)),
117                'green': ((0., 0, 0), (0.125,0, 0), (0.375,1, 1), (0.64,1, 1),
118                          (0.91,0,0), (1, 0, 0)),
119                'blue':  ((0., 0.5, 0.5), (0.11, 1, 1), (0.34, 1, 1), (0.65,0, 0),
120                          (1, 0, 0))}
121 
122 cmap_data = { 'jet' : _jet_data }
123 
124 def make_cmap(name, n=256):
125     data = cmap_data[name]
126     xs = np.linspace(0.0, 1.0, n)
127     channels = []
128     eps = 1e-6
129     for ch_name in ['blue', 'green', 'red']:
130         ch_data = data[ch_name]
131         xp, yp = [], []
132         for x, y1, y2 in ch_data:
133             xp += [x, x+eps]
134             yp += [y1, y2]
135         ch = np.interp(xs, xp, yp)
136         channels.append(ch)
137     return np.uint8(np.array(channels).T*255)
138 
139 def nothing(*arg, **kw):
140     pass
141 
142 def clock():
143     return cv2.getTickCount() / cv2.getTickFrequency()
144 
145 @contextmanager
146 def Timer(msg):
147     print(msg, '...',)
148     start = clock()
149     try:
150         yield
151     finally:
152         print("%.2f ms" % ((clock()-start)*1000))
153 
154 class StatValue:
155     def __init__(self, smooth_coef = 0.5):
156         self.value = None
157         self.smooth_coef = smooth_coef
158     def update(self, v):
159         if self.value is None:
160             self.value = v
161         else:
162             c = self.smooth_coef
163             self.value = c * self.value + (1.0-c) * v
164 
165 class RectSelector:
166     def __init__(self, win, callback):
167         self.win = win
168         self.callback = callback
169         cv2.setMouseCallback(win, self.onmouse)
170         self.drag_start = None
171         self.drag_rect = None
172     def onmouse(self, event, x, y, flags, param):
173         x, y = np.int16([x, y]) # BUG
174         if event == cv2.EVENT_LBUTTONDOWN:
175             self.drag_start = (x, y)
176         if self.drag_start:
177             if flags & cv2.EVENT_FLAG_LBUTTON:
178                 xo, yo = self.drag_start
179                 x0, y0 = np.minimum([xo, yo], [x, y])
180                 x1, y1 = np.maximum([xo, yo], [x, y])
181                 self.drag_rect = None
182                 if x1-x0 > 0 and y1-y0 > 0:
183                     self.drag_rect = (x0, y0, x1, y1)
184             else:
185                 rect = self.drag_rect
186                 self.drag_start = None
187                 self.drag_rect = None
188                 if rect:
189                     self.callback(rect)
190     def draw(self, vis):
191         if not self.drag_rect:
192             return False
193         x0, y0, x1, y1 = self.drag_rect
194         cv2.rectangle(vis, (x0, y0), (x1, y1), (0, 255, 0), 2)
195         return True
196     @property
197     def dragging(self):
198         return self.drag_rect is not None
199 
200 
201 def grouper(n, iterable, fillvalue=None):
202     '''grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx'''
203     args = [iter(iterable)] * n
204     if PY3:
205         output = it.zip_longest(fillvalue=fillvalue, *args)
206     else:
207         output = it.izip_longest(fillvalue=fillvalue, *args)
208     return output
209 
210 def mosaic(w, imgs):
211     '''Make a grid from images.
212 
213     w    -- number of grid columns
214     imgs -- images (must have same size and format)
215     '''
216     imgs = iter(imgs)
217     if PY3:
218         img0 = next(imgs)
219     else:
220         img0 = imgs.next()
221     pad = np.zeros_like(img0)
222     imgs = it.chain([img0], imgs)
223     rows = grouper(w, imgs, pad)
224     return np.vstack(map(np.hstack, rows))
225 
226 def getsize(img):
227     h, w = img.shape[:2]
228     return w, h
229 
230 def mdot(*args):
231     return reduce(np.dot, args)
232 
233 def draw_keypoints(vis, keypoints, color = (0, 255, 255)):
234     for kp in keypoints:
235             x, y = kp.pt
236             cv2.circle(vis, (int(x), int(y)), 2, color)

 

video.py

  1 #!/usr/bin/env python
  2 
  3 '''
  4 Video capture sample.
  5 
  6 Sample shows how VideoCapture class can be used to acquire video
  7 frames from a camera of a movie file. Also the sample provides
  8 an example of procedural video generation by an object, mimicking
  9 the VideoCapture interface (see Chess class).
 10 
 11 'create_capture' is a convinience function for capture creation,
 12 falling back to procedural video in case of error.
 13 
 14 Usage:
 15     video.py [--shotdir <shot path>] [source0] [source1] ...'
 16 
 17     sourceN is an
 18      - integer number for camera capture
 19      - name of video file
 20      - synth:<params> for procedural video
 21 
 22 Synth examples:
 23     synth:bg=../data/lena.jpg:noise=0.1
 24     synth:class=chess:bg=../data/lena.jpg:noise=0.1:size=640x480
 25 
 26 Keys:
 27     ESC    - exit
 28     SPACE  - save current frame to <shot path> directory
 29 
 30 '''
 31 
 32 # Python 2/3 compatibility
 33 from __future__ import print_function
 34 
 35 import numpy as np
 36 from numpy import pi, sin, cos
 37 
 38 import cv2
 39 
 40 # built-in modules
 41 from time import clock
 42 
 43 # local modules
 44 import common
 45 
 46 class VideoSynthBase(object):
 47     def __init__(self, size=None, noise=0.0, bg = None, **params):
 48         self.bg = None
 49         self.frame_size = (640, 480)
 50         if bg is not None:
 51             self.bg = cv2.imread(bg, 1)
 52             h, w = self.bg.shape[:2]
 53             self.frame_size = (w, h)
 54 
 55         if size is not None:
 56             w, h = map(int, size.split('x'))
 57             self.frame_size = (w, h)
 58             self.bg = cv2.resize(self.bg, self.frame_size)
 59 
 60         self.noise = float(noise)
 61 
 62     def render(self, dst):
 63         pass
 64 
 65     def read(self, dst=None):
 66         w, h = self.frame_size
 67 
 68         if self.bg is None:
 69             buf = np.zeros((h, w, 3), np.uint8)
 70         else:
 71             buf = self.bg.copy()
 72 
 73         self.render(buf)
 74 
 75         if self.noise > 0.0:
 76             noise = np.zeros((h, w, 3), np.int8)
 77             cv2.randn(noise, np.zeros(3), np.ones(3)*255*self.noise)
 78             buf = cv2.add(buf, noise, dtype=cv2.CV_8UC3)
 79         return True, buf
 80 
 81     def isOpened(self):
 82         return True
 83 
 84 class Chess(VideoSynthBase):
 85     def __init__(self, **kw):
 86         super(Chess, self).__init__(**kw)
 87 
 88         w, h = self.frame_size
 89 
 90         self.grid_size = sx, sy = 10, 7
 91         white_quads = []
 92         black_quads = []
 93         for i, j in np.ndindex(sy, sx):
 94             q = [[j, i, 0], [j+1, i, 0], [j+1, i+1, 0], [j, i+1, 0]]
 95             [white_quads, black_quads][(i + j) % 2].append(q)
 96         self.white_quads = np.float32(white_quads)
 97         self.black_quads = np.float32(black_quads)
 98 
 99         fx = 0.9
100         self.K = np.float64([[fx*w, 0, 0.5*(w-1)],
101                         [0, fx*w, 0.5*(h-1)],
102                         [0.0,0.0,      1.0]])
103 
104         self.dist_coef = np.float64([-0.2, 0.1, 0, 0])
105         self.t = 0
106 
107     def draw_quads(self, img, quads, color = (0, 255, 0)):
108         img_quads = cv2.projectPoints(quads.reshape(-1, 3), self.rvec, self.tvec, self.K, self.dist_coef) [0]
109         img_quads.shape = quads.shape[:2] + (2,)
110         for q in img_quads:
111             cv2.fillConvexPoly(img, np.int32(q*4), color, cv2.LINE_AA, shift=2)
112 
113     def render(self, dst):
114         t = self.t
115         self.t += 1.0/30.0
116 
117         sx, sy = self.grid_size
118         center = np.array([0.5*sx, 0.5*sy, 0.0])
119         phi = pi/3 + sin(t*3)*pi/8
120         c, s = cos(phi), sin(phi)
121         ofs = np.array([sin(1.2*t), cos(1.8*t), 0]) * sx * 0.2
122         eye_pos = center + np.array([cos(t)*c, sin(t)*c, s]) * 15.0 + ofs
123         target_pos = center + ofs
124 
125         R, self.tvec = common.lookat(eye_pos, target_pos)
126         self.rvec = common.mtx2rvec(R)
127 
128         self.draw_quads(dst, self.white_quads, (245, 245, 245))
129         self.draw_quads(dst, self.black_quads, (10, 10, 10))
130 
131 
132 classes = dict(chess=Chess)
133 
134 presets = dict(
135     empty = 'synth:',
136     lena = 'synth:bg=../data/lena.jpg:noise=0.1',
137     chess = 'synth:class=chess:bg=../data/lena.jpg:noise=0.1:size=640x480'
138 )
139 
140 
141 def create_capture(source = 0, fallback = presets['chess']):
142     '''source: <int> or '<int>|<filename>|synth [:<param_name>=<value> [:...]]'
143     '''
144     source = str(source).strip()
145     chunks = source.split(':')
146     # handle drive letter ('c:', ...)
147     if len(chunks) > 1 and len(chunks[0]) == 1 and chunks[0].isalpha():
148         chunks[1] = chunks[0] + ':' + chunks[1]
149         del chunks[0]
150 
151     source = chunks[0]
152     try: source = int(source)
153     except ValueError: pass
154     params = dict( s.split('=') for s in chunks[1:] )
155 
156     cap = None
157     if source == 'synth':
158         Class = classes.get(params.get('class', None), VideoSynthBase)
159         try: cap = Class(**params)
160         except: pass
161     else:
162         cap = cv2.VideoCapture(source)
163         if 'size' in params:
164             w, h = map(int, params['size'].split('x'))
165             cap.set(cv2.CAP_PROP_FRAME_WIDTH, w)
166             cap.set(cv2.CAP_PROP_FRAME_HEIGHT, h)
167     if cap is None or not cap.isOpened():
168         print('Warning: unable to open video source: ', source)
169         if fallback is not None:
170             return create_capture(fallback, None)
171     return cap
172 
173 if __name__ == '__main__':
174     import sys
175     import getopt
176 
177     print(__doc__)
178 
179     args, sources = getopt.getopt(sys.argv[1:], '', 'shotdir=')
180     args = dict(args)
181     shotdir = args.get('--shotdir', '.')
182     if len(sources) == 0:
183         sources = [ 0 ]
184 
185     caps = list(map(create_capture, sources))
186     shot_idx = 0
187     while True:
188         imgs = []
189         for i, cap in enumerate(caps):
190             ret, img = cap.read()
191             imgs.append(img)
192             cv2.imshow('capture %d' % i, img)
193         ch = 0xFF & cv2.waitKey(1)
194         if ch == 27:
195             break
196         if ch == ord(' '):
197             for i, img in enumerate(imgs):
198                 fn = '%s/shot_%d_%03d.bmp' % (shotdir, i, shot_idx)
199                 cv2.imwrite(fn, img)
200                 print(fn, 'saved')
201             shot_idx += 1
202     cv2.destroyAllWindows()

 

motempl.py

 

 1 #!/usr/bin/env python
 2 
 3 import numpy as np
 4 import cv2
 5 import video
 6 from common import nothing, clock, draw_str
 7 
 8 MHI_DURATION = 0.5
 9 DEFAULT_THRESHOLD = 32
10 MAX_TIME_DELTA = 0.25
11 MIN_TIME_DELTA = 0.05
12 
13 
14 def draw_motion_comp(vis, (x, y, w, h), angle, color):
15     cv2.rectangle(vis, (x, y), (x + w, y + h), (0, 255, 0))
16     r = min(w / 2, h / 2)
17     cx, cy = x + w / 2, y + h / 2
18     angle = angle * np.pi / 180
19     cv2.circle(vis, (cx, cy), r, color, 3)
20     cv2.line(vis, (cx, cy), (int(cx + np.cos(angle) * r), int(cy + np.sin(angle) * r)), color, 3)
21 
22 
23 if __name__ == '__main__':
24     import sys
25 
26     try:
27         video_src = sys.argv[1]
28     except:
29         video_src = 0
30 
31     cv2.namedWindow('motempl')
32     visuals = ['input', 'frame_diff', 'motion_hist', 'grad_orient']
33     cv2.createTrackbar('visual', 'motempl', 2, len(visuals) - 1, nothing)
34     cv2.createTrackbar('threshold', 'motempl', DEFAULT_THRESHOLD, 255, nothing)
35 
36     cam = video.create_capture(video_src, fallback='synth:class=chess:bg=../cpp/lena.jpg:noise=0.01')
37     ret, frame = cam.read()
38     h, w = frame.shape[:2]
39     prev_frame = frame.copy()
40     motion_history = np.zeros((h, w), np.float32)
41     hsv = np.zeros((h, w, 3), np.uint8)
42     hsv[:, :, 1] = 255
43     while True:
44         ret, frame = cam.read()
45         frame_diff = cv2.absdiff(frame, prev_frame)
46         gray_diff = cv2.cvtColor(frame_diff, cv2.COLOR_BGR2GRAY)
47         thrs = cv2.getTrackbarPos('threshold', 'motempl')
48         ret, motion_mask = cv2.threshold(gray_diff, thrs, 1, cv2.THRESH_BINARY)
49         timestamp = clock()
50         cv2.motempl.updateMotionHistory(motion_mask, motion_history, timestamp, MHI_DURATION)
51         mg_mask, mg_orient = cv2.motempl.calcMotionGradient(motion_history, MAX_TIME_DELTA, MIN_TIME_DELTA, apertureSize=5)
52         seg_mask, seg_bounds = cv2.motempl.segmentMotion(motion_history, timestamp, MAX_TIME_DELTA)
53 
54         visual_name = visuals[cv2.getTrackbarPos('visual', 'motempl')]
55         if visual_name == 'input':
56             vis = frame.copy()
57         elif visual_name == 'frame_diff':
58             vis = frame_diff.copy()
59         elif visual_name == 'motion_hist':
60             vis = np.uint8(np.clip((motion_history - (timestamp - MHI_DURATION)) / MHI_DURATION, 0, 1) * 255)
61             vis = cv2.cvtColor(vis, cv2.COLOR_GRAY2BGR)
62         elif visual_name == 'grad_orient':
63             hsv[:, :, 0] = mg_orient / 2
64             hsv[:, :, 2] = mg_mask * 255
65             vis = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
66 
67         for i, rect in enumerate([(0, 0, w, h)] + list(seg_bounds)):
68             x, y, rw, rh = rect
69             area = rw * rh
70             if area < 64 ** 2:
71                 continue
72             silh_roi = motion_mask[y:y + rh, x:x + rw]
73             orient_roi = mg_orient[y:y + rh, x:x + rw]
74             mask_roi = mg_mask[y:y + rh, x:x + rw]
75             mhi_roi = motion_history[y:y + rh, x:x + rw]
76             if cv2.norm(silh_roi, cv2.NORM_L1) < area * 0.05:
77                 continue
78             angle = cv2.motempl.calcGlobalOrientation(orient_roi, mask_roi, mhi_roi, timestamp, MHI_DURATION)
79             color = ((255, 0, 0), (0, 0, 255))[i == 0]
80             draw_motion_comp(vis, rect, angle, color)
81 
82         draw_str(vis, (20, 20), visual_name)
83         cv2.imshow('motempl', vis)
84 
85         prev_frame = frame.copy()
86         if 0xFF & cv2.waitKey(5) == 27:
87             break
88     cv2.destroyAllWindows()

 

3.运行结果:

1 python motempl.py camera2.mov //第三个参赛不加的话是直接开启摄像头

转载于:https://www.cnblogs.com/asmer-stone/p/5091224.html

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenCV_contrib库添加到OpenCV 3.1.0需要按照以下步骤进行操作: 1. 下载OpenCV_contrib库:打开浏览器,进入OpenCV官方网站(https://opencv.org/),找到对应版本(OpenCV 3.1.0)的OpenCV_contrib库。下载完成后,解压缩库文件。 2. 下载CMake工具:进入CMake官方网站(https://cmake.org/),下载适用于Windows的CMake安装程序。 3. 安装CMake工具:运行下载的CMake安装程序,按照提示进行安装。安装完成后,在开始菜单找到“CMake”文件夹,打开“CMake”文件夹,然后打开“CMake (cmake-gui)”。 4. 配置CMake:在CMake GUI界面,点击“Browse Source”按钮,选择OpenCV 3.1.0源代码文件夹。然后,在“Browse Build”按钮旁边的输入框,输入一个新的文件夹路径,用于生成OpenCV 3.1.0的构建文件。点击“Configure”按钮,选择合适的编译器,然后点击“Finish”按钮等待配置完成。 5. 配置OpenCV_contrib库:在CMake GUI界面,找到“OPENCV_EXTRA_MODULES_PATH”选项,将其设置为Opencv_contrib库所在文件夹的路径。点击“Configure”按钮,等待配置完成。 6. 编译OpenCV 3.1.0:点击CMake GUI界面的“Generate”按钮,生成OpenCV 3.1.0的构建文件。然后,在命令提示符,进入OpenCV 3.1.0构建文件所在的路径。运行以下命令编译OpenCV 3.1.0: ```shell cmake --build . --config Release ``` 等待编译过程完成。 7. 添加环境变量:将OpenCV 3.1.0编译生成的bin文件夹添加到系统的环境变量PATH,以便能够在命令提示符直接运行OpenCV命令。 8. 完成:至此,你已经成功将OpenCV_contrib库添加到OpenCV 3.1.0了。您可以在编程项目使用OpenCV_contrib库的功能了。 请注意,这只是一种添加OpenCV_contrib库的方法,具体步骤可能会因不同的环境和配置而有所差异。因此,建议在操作前仔细阅读官方文档和教程,并参考可信的技术资源。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值