问题描述
在 macOS 10.15.2下使用 tkinter 库 Entry 输入框,无法输入中文,不管怎么样都只能输入英文,只能复制进去中文,交互体验很不好ಥ_ಥ。
我的版本是 macOS 10.15.2,python 3.7.5。
Python(KK 英语发音:/ˈpaɪθən/), 是一种面向对象、直译式计算机程序设计语言,由Guido van Rossum于1989年底发明,第一个公开发行版发行于1991年。Python语法简洁而清晰,具有丰富和强大的类库。它常被昵称为胶水语言,它能够很轻松的把用其他语言制作的各种模块(尤其是C/C++)轻松地联结在一起。
在 macOS 10.15.2下使用 tkinter 库 Entry 输入框,无法输入中文,不管怎么样都只能输入英文,只能复制进去中文,交互体验很不好ಥ_ಥ。
我的版本是 macOS 10.15.2,python 3.7.5。
前提:代码中设置了arg paser,需要手动设置,VS code的debug没有简洁的添加参数的方式。
解决方式如下:
打开Debug->Open Configurations/ Add Configurations
1 2 3 4 5 |
# Python2 $ pip install requests-html # Python3 # pip3 install requests-html |
即可安装该模块。
例子如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#coding=utf-8 from bs4 import BeautifulSoup import requests from requests_html import HTMLSession #使用requests抓取页面内容,并将响应赋值给page变量 html = requests.get('https://xcx.xzlzq.net/#/liftDetail?registerCode=31103301042010020002') session = HTMLSession() first_page = session.get('https://xcx.xzlzq.net/#/liftDetail?registerCode=31103301042010020002') first_page.html.render(sleep=5) #使用content属性获取页面的源页面 #使用BeautifulSoap解析,内容传递到BeautifulSoap类 soup = BeautifulSoup(first_page.html.html,'lxml') links = soup.find_all('div',class_='content') #link的内容就是div,我们取它的span内容就是我们需要段子的内容 for link in links: print(link.span.get_text()) |
安装依赖
1 2 3 4 5 6 7 |
$ python -m pip install --upgrade pip --user $ python -m pip install Pillow --user $ python -m pip install Numpy --user $ python -m pip install OpenCV-Python --user |
源代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 |
#!/usr/bin/python # -*- coding: UTF-8 -*- import os import sys if sys.version_info < (3, 0): import Tkinter as tk # 导入 Tkinter 库 from tkFileDialog import askopenfilename, askdirectory else : import tkinter as tk # 导入 Tkinter 库 from tkinter.filedialog import askopenfilename, askdirectory from PIL import Image, ImageTk, ImageDraw from time import sleep import numpy as np import cv2 as cv import collections DEF_WIDTH = 1080 DEF_HEIGHT = 720 IMAGE_HEIGHT = 720 FRAME_LEFT_WIDTH = 360 # 太小的选定区域我们需要丢弃,防止误操作 MINI_RECT_AREA = 20 class RawImageEditor: def __init__(self, win, img, rects): #变量X和Y用来记录鼠标左键按下的位置 self.X = tk.IntVar(value=0) self.Y = tk.IntVar(value=0) self.sel = False self.lastDraw = None self.lastDraws = [] self.imageScale = 1.0 self.dispWidth = DEF_WIDTH # 图片显示区域的最大高度,宽度 self.dispHeight = DEF_HEIGHT self.rawImage = img self.calcImageScale(self.rawImage) self.dispWidth = int(self.imageScale * self.rawImage.width) self.dispHeight = int(self.imageScale * self.rawImage.height) # 图片缩放 self.dispImage = self.rawImage.resize((self.dispWidth, self.dispHeight)) # 选择区域 self.selPositions = [] for r in rects : self.selPositions.append((r[0] * self.imageScale, r[1] * self.imageScale, r[2] * self.imageScale, r[3] * self.imageScale)) #创建顶级组件容器 self.top = tk.Toplevel(win, width=self.dispWidth, height=self.dispHeight) #不显示最大化、最小化按钮 self.top.overrideredirect(True) #center window on desktop nScreenWid, nScreenHei = self.top.maxsize() winPos = '%sx%s+%s+%s' % (int(self.top.winfo_reqwidth()), int(self.top.winfo_reqheight()), int((nScreenWid - self.top.winfo_reqwidth())/2), int((nScreenHei - self.top.winfo_reqheight())/2)) self.top.geometry(winPos) # Make topLevelWindow remain on top until destroyed, or attribute changes. self.top.attributes('-topmost', 'true') self.canvas = tk.Canvas(self.top, bg='white', width=self.dispWidth, height=self.dispHeight) self.tkImage = ImageTk.PhotoImage(self.dispImage) self.canvas.create_image(self.dispWidth//2, self.dispHeight//2, image=self.tkImage) for r in self.selPositions : draw = self.canvas.create_rectangle(r[0], r[1], r[2], r[3], outline='green') self.lastDraws.append(draw) #鼠标左键按下的位置 def onLeftButtonDown(event): self.X.set(event.x) self.Y.set(event.y) #开始截图 self.sel = True #重新绘制已经选择的区域 for draw in self.lastDraws : self.canvas.delete(draw) self.lastDraws = [] for r in self.selPositions : draw = self.canvas.create_rectangle(r[0], r[1], r[2], r[3], outline='green') self.lastDraws.append(draw) self.canvas.bind('<Button-1>', onLeftButtonDown) #鼠标左键移动,显示选取的区域 def onLeftButtonMove(event): if not self.sel: return try: #删除刚画完的图形,要不然鼠标移动的时候是黑乎乎的一片矩形 self.canvas.delete(self.lastDraw) except Exception as e: pass self.lastDraw = self.canvas.create_rectangle(self.X.get(), self.Y.get(), event.x, event.y, outline='green') self.canvas.bind('<B1-Motion>', onLeftButtonMove) #获取鼠标左键抬起的位置,保存区域截图 def onLeftButtonUp(event): if not self.sel: return self.sel = False sleep(0.1) #考虑鼠标左键从右下方按下而从左上方抬起的截图 left, right = sorted([self.X.get(), event.x]) top, bottom = sorted([self.Y.get(), event.y]) if (right - left) * (bottom - top) > MINI_RECT_AREA : self.selPositions.append((left,top,right,bottom)) #self.top.destroy() #鼠标右键按下 def onRightButtonDown(event): self.sel = False self.top.destroy() self.canvas.bind('<Button-2>', onRightButtonDown) self.canvas.bind('<ButtonRelease-1>', onLeftButtonUp) self.canvas.pack(fill=tk.BOTH, expand=tk.YES) def calcImageScale(self, image) : w = image.width h = image.height self.imageScale = 1.0 # 计算最小的缩放比例,保证原始宽高比 if w > self.dispWidth and h > self.dispHeight : ws = self.dispWidth * 1.0 / w hs = self.dispHeight * 1.0 / h if ws < hs : self.imageScale = ws else : self.imageScale = hs elif w > self.dispWidth and h < self.dispHeight : self.imageScale = self.dispWidth * 1.0 / w elif w < self.dispWidth and h > self.dispHeight : self.imageScale = self.dispHeight * 1.0 / h def waitForWindow(self, win) : win.wait_window(self.top) def selectedPositions(self) : # 转换为原始像素位置 realPos = [] for r in self.selPositions : realPos.append((r[0] / self.imageScale, r[1] / self.imageScale, r[2] / self.imageScale, r[3] / self.imageScale)) return realPos class MainWin(tk.Tk): def __init__(self): if sys.version_info >= (3, 0): super().__init__() else : tk.Tk.__init__(self) self.title('图像处理工具') self.geometry('{}x{}'.format(DEF_WIDTH, DEF_HEIGHT)) self.rawImagePath = '' self.rawImage = None # self.rawImage 原始图像,未经过缩放处理 self.transRawImage = None # self.transRawImage 经过转换处理之后的原始图像,没有经过缩放处理 self.dispImage = None # self.dispImage 显示图像,可能经过缩放处理 self.imageScale = 1.0 # 图片缩放比例,根据缩放比例进行显示的时候的缩放处理,后期选择区域的时候,需要进行缩放还原 self.leftFrameWidth = FRAME_LEFT_WIDTH self.frameDispHeight = DEF_HEIGHT # 整个窗口的高度 self.labelTextHeight = 18 # 文本标签的高度 self.btnHeight = 30 # 按钮的高度 self.brightnessScale = tk.StringVar() # 亮度比 self.brightnessScale.set('1.0') self.defSavePath = '' # 默认保存路径 self.imageDispWidth = IMAGE_HEIGHT # 图片显示区域的最大高度,宽度 self.imageDispHeight = self.frameDispHeight / 2 - self.labelTextHeight * 2 self.liRect = collections.OrderedDict() # 选择区域 self.rawImageEditor = None self.currentListBoxSelIdx = None #当前选择的项目 self.setupUI() def scaleDisplayImage(self, image) : w = image.width h = image.height self.imageScale = 1.0 # 计算最小的缩放比例,保证原始宽高比 if w > self.imageDispWidth and h > self.imageDispHeight : ws = self.imageDispWidth * 1.0 / w hs = self.imageDispHeight * 1.0 / h if ws < hs : self.imageScale = ws else : self.imageScale = hs elif w > self.imageDispWidth and h < self.imageDispHeight : self.imageScale = self.imageDispWidth * 1.0 / w elif w < self.imageDispWidth and h > self.imageDispHeight : self.imageScale = self.imageDispHeight * 1.0 / h # 图片缩放 return image.resize((int(self.imageScale * w), int(self.imageScale * h))) def loadImageCfgFile(self, imf): (path, name) = os.path.split(imf) cfgname = imf + '.txt' if (not os.path.exists(cfgname)) or (not os.path.isfile(cfgname)) : cfgname = os.path.join(path, 'mask', name) + '.txt' if (not os.path.exists(cfgname)) or (not os.path.isfile(cfgname)) : cfgname = os.path.join(path, 'cfg', name) + '.txt' self.liRect.clear() if os.path.exists(cfgname) and os.path.isfile(cfgname) : with open(cfgname, "r") as f: lines = f.readlines() for line in lines: rs = line.split(',') r = (float(rs[0].strip()), float(rs[1].strip()), float(rs[2].strip()), float(rs[3].strip())) if len(rs) > 4 : self.liRect[r] = rs[4].strip() else : self.liRect[r] = '' # 打开图片时使用,传值(图)给展示函数 def openAndDisplayImage(self): imF = self.selectImageFile() if '' != imF : self.rawImagePath = imF self.loadImageCfgFile(self.rawImagePath) self.drawListBox() self.rawImage = Image.open(self.rawImagePath) self.rawImage = self.rawImage.convert('RGBA') self.drawRawImageDisp() self.image_l_trans.image = None self.transRawImage = None def drawListBox(self): self.l_box.delete(0, tk.END) for r in self.liRect.keys(): r = '{},{},{},{}'.format(round(r[0],1), round(r[1],1), round(r[2],1), round(r[3],1)) self.l_box.insert(0, r) def drawRawImageDisp(self, selItems=[]): self.dispImage = self.scaleDisplayImage(self.rawImage) self.dispImage = self.dispImage.convert('RGB') draw = ImageDraw.Draw(self.dispImage) rs = list(self.liRect.keys()) for i in range(len(rs)) : r = rs[i] if i in selItems : draw.rectangle((r[0] * self.imageScale, r[1] * self.imageScale, r[2] * self.imageScale, r[3] * self.imageScale), outline = "red") else : draw.rectangle((r[0] * self.imageScale, r[1] * self.imageScale, r[2] * self.imageScale, r[3] * self.imageScale), outline = "green") img = ImageTk.PhotoImage(self.dispImage) self.image_l_raw.config(image=img) self.image_l_raw.image = img def deleteSelectedItemFromListBox(self): #print(self.l_box.get(self.l_box.curselection())) idx = self.l_box.curselection() if len(idx) > 0 and (None == self.rawImageEditor) : ro = collections.OrderedDict() rs = self.liRect.keys() for i in range(len(rs)) : if i not in idx : r = rs[i] ro[r] = self.liRect[r] self.liRect = ro self.drawListBox() self.drawRawImageDisp() # 打开图片时使用,获得地址 def selectImageFile(self): path = tk.StringVar() file_entry = tk.Entry(self, state='readonly', text=path) path_ = askopenfilename() path.set(path_) return file_entry.get() def rawImageLabelClicked(self, event): if (None != self.rawImage) and (None == self.rawImageEditor) : self.rawImageEditor = RawImageEditor(self, self.rawImage, self.liRect.keys()) self.rawImageEditor.waitForWindow(self.image_l_raw) rs = self.rawImageEditor.selectedPositions() trs = collections.OrderedDict() for k in rs : if k in self.liRect : trs[k] = self.liRect[k] else: trs[k] = '' self.liRect = trs self.rawImageEditor = None self.drawListBox() self.drawRawImageDisp() def onRectListboxSelect(self, event): idx = self.l_box.curselection() if len(idx) > 0 and (self.currentListBoxSelIdx != idx) : self.currentListBoxSelIdx = idx ctx = '' rs = list(self.liRect.keys()) for i in range(len(self.currentListBoxSelIdx)) : v = self.currentListBoxSelIdx[i] k = rs[v] ctx = ctx + self.liRect[k] if i < len(self.currentListBoxSelIdx)-1 : ctx = ctx + ',' self.edtListBoxSel.delete(0, tk.END) self.edtListBoxSel.insert(0, ctx) self.drawRawImageDisp(idx) def onEdtListBoxComplete(self, event): idx = self.l_box.curselection() if (len(idx) > 0) and (self.currentListBoxSelIdx == idx) : ctx = self.edtListBoxSel.get().strip() ctx = ctx.split(',') while len(idx) > len(ctx) : ctx.append('') rs = list(self.liRect.keys()) n = 0 for i in idx : r = rs[i] self.liRect[r] = ctx[n] n = n + 1 def drawTransImageDisp(self): transImage = self.scaleDisplayImage(self.transRawImage) transImage = transImage.convert('L') img = ImageTk.PhotoImage(transImage) self.image_l_trans.config(image=img) self.image_l_trans.image = img def doTransRawImage(self): self.transRawImage = Image.new('L', (self.rawImage.width, self.rawImage.height)) rs = self.liRect.keys() for r in rs : im = self.rawImage.crop(r) cv_im = cv.cvtColor(np.asarray(im), cv.COLOR_RGB2BGR) hsv = cv.cvtColor(cv_im, cv.COLOR_BGR2HSV) _, _, v = cv.split(hsv) avg = np.average(v.flatten()) pixels = im.load() scale = float(self.brightnessScale.get()) for j in range(im.height) : for i in range(im.width) : hv = v[j,i] if hv < avg * scale: #im.putpixel((i, j), 0) # pixels[i, j] = 0 '''else : im.putpixel((i, j), (255, 255, 255, 255))''' self.transRawImage.paste(im, (int(r[0]),int(r[1])), mask = None) self.drawTransImageDisp() def onTransRawImageBtnClicked(self): if None != self.rawImage : self.doTransRawImage() def saveTransCfg(self, pth): (path,name) = os.path.split(self.rawImagePath) cfg = os.path.join(pth, 'cfg') if os.path.exists(cfg) and os.path.isdir(cfg) : cfgname = os.path.join(cfg, name) + '.txt' else : cfgname = os.path.join(pth, name) + '.txt' with open(cfgname, "w") as f: for r in self.liRect.keys() : v = self.liRect[r] line = '{},{},{},{},{}\n'.format(r[0], r[1], r[2], r[3], v) f.write(line) def saveCombinedImage(self, pth): im_A = cv.cvtColor(np.array(self.rawImage), cv.COLOR_RGB2BGR) im_B = cv.cvtColor(np.array(self.transRawImage), cv.COLOR_RGB2BGR) im_AB = np.concatenate([im_A, im_B], 1) ext = os.path.splitext(self.rawImagePath)[-1] ext = ext.lower() name = os.path.basename(self.rawImagePath) sp = name.split('.')[:-1] comb = os.path.join(pth, 'comb') if os.path.exists(comb) and os.path.isdir(comb) : name = sp[0] + ext pth = comb else : name = sp[0] + '_comb' + ext path_AB = os.path.join(pth, name) cv.imwrite(path_AB, im_AB) def saveTransImage(self, path): ext = os.path.splitext(self.rawImagePath)[-1] ext = ext.lower() (path,name) = os.path.split(self.rawImagePath) mask = os.path.join(path, 'mask') fn = name.split('.')[:-1] if os.path.exists(mask) and os.path.isdir(mask) : fn = fn[0] + ext else : fn = fn[0] + '_mask' + ext im = os.path.join(mask, fn) if not im.endswith(ext) : im = im + ext self.transRawImage.save(im) def saveTransInformation(self, path): if '' != path : self.saveTransImage(path) self.saveTransCfg(path) self.saveCombinedImage(path) def onSaveTransRawImageBtnClicked(self): if None != self.transRawImage : (path,name) = os.path.split(self.rawImagePath) dirname = askdirectory(initialdir = os.path.expanduser(path), title = '保存结果') if '' != dirname : self.defSavePath = dirname self.saveTransInformation(self.defSavePath) def onDefaultSaveTransRawImageBtnClicked(self) : if (None != self.transRawImage) and ('' != self.defSavePath) : self.saveTransInformation(self.defSavePath) def setupUI(self): # 左边菜单栏 left_f = tk.Frame(self, height=self.frameDispHeight, width=self.leftFrameWidth) left_f.pack(side=tk.LEFT) # 各种功能按钮名称及位置 btnOpen = tk.Button(left_f, text='打开图像', command=self.openAndDisplayImage) btnOpen.place(y=25, x=30, width=300, height=self.btnHeight) btnTrans = tk.Button(left_f, text='处理图像', command=self.onTransRawImageBtnClicked) btnTrans.place(y=75, x=30, width=300, height=self.btnHeight) l_selRect = tk.Label(left_f, text = '鼠标选定区域') l_selRect.place(x=0, y=125, width=self.leftFrameWidth, height=self.labelTextHeight) '''列表''' self.l_box = tk.Listbox(left_f, exportselection=False) # 创建两个列表组件 self.l_box.place(x=1, y=125+self.labelTextHeight, width=self.leftFrameWidth-2, height=270) self.l_box.bind('<<ListboxSelect>>', self.onRectListboxSelect) self.drawListBox() # 选中列表注释 ledt = tk.Label(left_f, text = '选中区域内容注释(回车结束):', anchor = 'w') ledt.place(x=1, y=420, width=self.leftFrameWidth-2) self.edtListBoxSel = tk.Entry(left_f) self.edtListBoxSel.place(x=1, y=440, width=self.leftFrameWidth-2) self.edtListBoxSel.bind('<Return>', self.onEdtListBoxComplete) # 亮度比例调节 tkScale = tk.Scale(left_f, from_=0.2, to=1.8, orient=tk.HORIZONTAL, resolution=0.1, length=self.leftFrameWidth-2, variable=self.brightnessScale, label = '亮度比:') tkScale.place(x=1, y=480) # 删除选定项 btnDel = tk.Button(left_f, text='删除选定项', command=self.deleteSelectedItemFromListBox) btnDel.place(y=550, x=30, width=300, height=self.btnHeight) btnSave = tk.Button(left_f, text='保存结果', command=self.onSaveTransRawImageBtnClicked) btnSave.place(y=600, x=30, width=300, height=self.btnHeight) btnDefSave = tk.Button(left_f, text='默认或上次位置保存', command=self.onDefaultSaveTransRawImageBtnClicked) btnDefSave.place(y=650, x=30, width=300, height=self.btnHeight) # 右侧图像显示栏 right_f = tk.Frame(self, height=self.frameDispHeight, width=self.imageDispWidth) right_f.pack(side=tk.RIGHT) l_rawT = tk.Label(right_f, text = '原始图片') l_rawT.place(x=0, y=0, width=self.imageDispWidth, height=self.labelTextHeight) self.image_l_raw = tk.Label(right_f, relief='ridge') self.image_l_raw.place(x=0, y=self.labelTextHeight, width=self.imageDispWidth, height=self.imageDispHeight) self.image_l_raw.bind("<Button-1>",self.rawImageLabelClicked) l_transT = tk.Label(right_f, text = '处理后图片') l_transT.place(x=0, y=self.labelTextHeight + self.imageDispHeight, width=self.imageDispWidth, height=self.labelTextHeight) self.image_l_trans = tk.Label(right_f, relief='ridge') self.image_l_trans.place(x=0, y=self.labelTextHeight + self.imageDispHeight + self.labelTextHeight, width=self.imageDispWidth, height=self.imageDispHeight) if __name__ == '__main__' : win = MainWin() # 进入消息循环 win.mainloop() |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
#!/usr/bin/python # -*- coding: UTF-8 -*- import sys import os #Python的标准库中的os模块包含普遍的操作系统功能 import re #引入正则表达式对象 import urllib #用于对URL进行编解码 if sys.version_info < (3, 0): from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler #导入HTTP处理相关的模块 else : from http.server import HTTPServer, BaseHTTPRequestHandler import cgi #文件上传处理 import base64 #base64编码 from io import BytesIO #本地文件读取 #自定义处理程序,用于处理HTTP请求 class EasyHTTPHandler(BaseHTTPRequestHandler): def do_RespHtml(self, html): self.protocal_version = 'HTTP/1.1' #设置协议版本 self.send_response(200) #设置响应状态码 self.send_header("Welcome", "Contect") #设置响应头 self.end_headers() if sys.version_info >= (3, 0): html = html.encode('utf-8') self.wfile.write(html) #输出响应内容 def do_ImageHtml(self, img): templateStr = ''' <html> <head> <title>EasyHttpServer</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <form enctype="multipart/form-data" method="post"> 选择图片:<input type="file" name="uploadImage" id="uploadImage" accept="image/png, image/jpeg"> <input type="submit" value="识别"> </form> <div>{0}</div> </body> </html> '''.format(img) self.do_RespHtml(templateStr) def do_FileRecv(self): form = cgi.FieldStorage( fp=self.rfile, headers=self.headers, environ={'REQUEST_METHOD':'POST', 'CONTENT_TYPE':self.headers['Content-Type'], } ) imageHtml = "" for field in form.keys(): field_item = form[field] filename = field_item.filename filevalue = field_item.value filesize = len(filevalue)#文件大小(字节) #print len(filevalue) #print (filename) ext = os.path.splitext(filename)[1] if sys.version_info >= (3, 0): filename = filename.encode('utf-8') with open(filename, 'wb') as f: f.write(filevalue) #将图片保存到内存中 f = BytesIO() with open(filename, 'rb') as img: f.write(img.read()) #从内存中取出bytes类型的图片 data = f.getvalue() #将bytes转成base64 data = base64.b64encode(data).decode() imageHtml += "<p> <image width='200px' src='data:image/" + ext + ";base64," + data + "'/> </p>" self.do_ImageHtml(imageHtml) def doIndexHtml(self): #获取URL #print 'URL=',self.path #页面输出模板字符串 templateStr = ''' <html> <head> <title>EasyHttpServer</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <form enctype="multipart/form-data" method="post"> 选择图片:<input type="file" name="uploadImage" id="uploadImage" accept="image/png, image/jpeg"> <input type="submit" value="上传"> </form> </body> </html> ''' self.do_RespHtml(templateStr) #处理GET请求 def do_GET(self): self.doIndexHtml() #处理POST请求 def do_POST(self): self.do_FileRecv() #启动服务函数 def start_server(port): http_server = HTTPServer(('', int(port)), EasyHTTPHandler) http_server.serve_forever() #设置一直监听并接收请求 #os.chdir('static') #改变工作目录到 static 目录 start_server(8000) #启动服务,监听8000端口 |
Visual Studio Code远程调试pytorch模型训练时,报错如下:
1 2 3 |
File "/home/xxxx/.vscode-server/extensions/ms-python.python-2019.5.18875/pythonFiles/lib/python/ptvsd/daemon.py", line 145, in start raise RuntimeError(‘already started’) RuntimeError: already started |
解决办法,在.py文件头添加如下语句:
1 2 |
import multiprocessing multiprocessing.set_start_method('spawn',True) |
更新:
如果你的工程是基于pytorch的,那么检查自己的dataLoader,是否使用了num_workers参数。当使用该参数时,可能会报上述错误。解决办法是将num_workers设置为0
1 添加清华源
命令行中直接使用以下命令
1 2 3 4 5 6 7 8 9 |
$ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ $ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ # pytorch $ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/ # 设置搜索时显示通道地址 $ conda config --set show_channel_urls yes |
2 添加中科大源
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ conda config --add channels https://mirrors.ustc.edu.cn/anaconda/pkgs/main/ $ conda config --add channels https://mirrors.ustc.edu.cn/anaconda/pkgs/free/ $ conda config --add channels https://mirrors.ustc.edu.cn/anaconda/cloud/conda-forge/ $ conda config --add channels https://mirrors.ustc.edu.cn/anaconda/cloud/msys2/ $ conda config --add channels https://mirrors.ustc.edu.cn/anaconda/cloud/bioconda/ $ conda config --add channels https://mirrors.ustc.edu.cn/anaconda/cloud/menpo/ $ conda config --set show_channel_urls yes |
将以上配置文件写在~/.condarc
中
1 |
$ vim ~/.condarc |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
channels: - defaults show_channel_urls: true default_channels: - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r custom_channels: conda-forge: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud msys2: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud bioconda: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud menpo: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud pytorch: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud simpleitk: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud |
在修改完成之后,一定要重新启动一个新的Shell
, 否则设置不生效。
1 2 3 4 5 6 7 8 |
(FOTS) $~/Source/FOTS.PyTorch$ bash build.sh Compiling crop_and_resize kernels by nvcc... Traceback (most recent call last): File "build.py", line 3, in <module> from torch.utils.ffi import create_extension File "~/.conda/envs/FOTS/lib/python2.7/site-packages/torch/utils/ffi/__init__.py", line 1, in <module> raise ImportError("torch.utils.ffi is deprecated. Please use cpp extensions instead.") ImportError: torch.utils.ffi is deprecated. Please use cpp extensions instead. |
最省事的情况是降级pytorch
版本到0.4
,强烈建议使用Anaconda
创建独立的Python
开发环境,然后在干净的环境中运行。
命令行下查看python和numpy的版本和安装位置
1、查看python版本
方法一:
1 |
$ python -V |
注意:‘-V‘中‘V’为大写字母,只有一个‘-’
方法二:
1 |
$ python --version |
注意:‘--version'中有两个‘-’
2、查看python安装位置
方法一:
1 |
$ python -c "import sys; print sys.executable" |
方法二:
1 2 3 |
$ python -c "import os; print os.sys.executable" $ python -c "import os; path = os.sys.executable;folder=path[0 : path.rfind(os.sep)]; print folder" |
3、查看Numpy版本
1 |
$ python -c "import numpy; print numpy.version.version" |
或
1 |
$ python -c "import numpy; print numpy.__version__" |
4、查看Numpy安装路径
1 |
$ python -c "import numpy; print numpy.__file__" |
注:按照查看Numpy版本和安装路径的方法,可以查看其他python包版本和安装路径。
macOS Mojave 10.14.2 llvm 7.0.1
1 2 3 4 5 6 7 |
$ brew install llvm --with-clang --with-python --with-lld $ export DYLD_LIBRARY_PATH=/usr/local/opt/llvm/lib $ export LLVM_VER=$(brew list --versions | grep llvm | sed 's/\([0-9]\).*/\1/g' | tr -cd "[0-9]") $ pip install clang |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#!/usr/bin/env python # -*- coding: utf-8 -*- """ Usage: call with <filename> <typename> """ import sys import clang.cindex # 也可以使用如下命令指定libclang的加载位置,这个动态库可以直接拷贝到其他机器上使用,是个独立库 # clang.cindex.Config.set_library_path('/usr/local/opt/llvm/lib') # 如下可以简化代码 # from clang.cindex import CursorKind # from clang.cindex import AccessSpecifier def find_typerefs(node, typename): """ Find all references to the type named 'typename' """ if node.kind.is_reference(): ref_node = node.get_definition() if ref_node : if ref_node.spelling == typename: print 'Found %s [line=%s, col=%s]' % ( typename, node.location.line, node.location.column) # Recurse for children of this node for c in node.get_children(): find_typerefs(c, typename) index = clang.cindex.Index.create() tu = index.parse(sys.argv[1]) print 'Translation unit:', tu.spelling find_typerefs(tu.cursor, sys.argv[2]) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
#!/usr/bin/env python # -*- coding: utf-8 -*- """ C++ linter using libclang. Call with [filenames] """ from __future__ import print_function from clang.cindex import Config, TypeKind, CursorKind, Index from pprint import pprint import platform import sys if platform.system() == "Linux": Config.set_library_file("/usr/lib/llvm-3.4/lib/libclang.so") else: Config.set_library_file("/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libclang.dylib") def error(out_errors, node, msg): error_msg = "{}:{}: {}".format(node.location.file, node.location.line, msg) out_errors.append(error_msg) print(error_msg, file=sys.stderr) def is_mut_ref(arg_type): if arg_type.kind in [TypeKind.POINTER, TypeKind.LVALUEREFERENCE, TypeKind.INCOMPLETEARRAY, TypeKind.CONSTANTARRAY]: if arg_type.kind in [TypeKind.POINTER, TypeKind.LVALUEREFERENCE]: pointee_type = arg_type.get_pointee() else: pointee_type = arg_type.get_array_element_type() # print("pointee_type.kind: {}".format(pointee_type.kind)) # print("pointee_type.is_const_qualified(): {}".format(pointee_type.is_const_qualified())) if not pointee_type.is_const_qualified(): return True return False def check_argument(out_errors, function, node, function_parse_progress): assert node.kind == CursorKind.PARM_DECL if function.kind == CursorKind.FUNCTION_DECL and function.spelling == "main": # Ignore main function return # print("") # print("node.spelling: {}".format(node.spelling)) # print("node.type.kind: {}".format(node.type.kind)) # print("node.type.get_ref_qualifier(): {}".format(node.type.get_ref_qualifier())) # print("node.type.is_const_qualified(): {}".format(node.type.is_const_qualified())) # pprint(dir(node)) name = node.spelling if not name: # Ignore nameless arguments (e.g. Foo(Foo&)) return if is_mut_ref(node.type): if name.startswith("o_"): function_parse_progress["state"] = "out" elif name.startswith("io_"): if function_parse_progress["state"] != "io": error(out_errors, node, "io_ arguments should be first") function_parse_progress["state"] = "io" else: error(out_errors, node, "Non-const reference/pointer/array argument should be prefixed with " \ "either o_ (for out) or io_ (for in-out), e.g. 'o_{}'".format(name)) else: if function_parse_progress["state"] == "out": error(out_errors, node, "input arguments should come before output arguments") function_parse_progress["state"] = "in" def do_lint(out_errors, node, root_file): if node.location.file and node.location.file.name != root_file.name: # This is ugly, but works. return # print("{}:{} node.kind: {}".format(node.location.file, node.location.line, node.kind)) # print("node.translation_unit: {}".format(node.translation_unit)) # # pprint(dir(node.translation_unit)) # print("node.location.file: {}".format(node.location.file)) # pprint(dir(node.location)) # exit() # CursorKind.CONSTRUCTOR excluded: references there are often stored, so not o_ or io_ if node.kind in [CursorKind.FUNCTION_DECL, CursorKind.CXX_METHOD]: # print("Found a function!") # print("node.spelling: {}".format(node.spelling)) # print("node.displayname: {}".format(node.displayname)) function_parse_progress = { "state": "io", # "io", "in" or "out" } for arg in node.get_arguments(): check_argument(out_errors, node, arg, function_parse_progress) # Recurse for children of this node for c in node.get_children(): do_lint(out_errors, c, root_file) def lint_file(filepath): index = Index.create() tu = index.parse(filepath) root_file = tu.get_file(tu.spelling) errors = [] do_lint(errors, tu.cursor, root_file) return errors def main(): if len(sys.argv) == 1: print("Usage: {} [filenames]".format(sys.argv[0])) return for filepath in sys.argv[1:]: lint_file(filepath) if __name__ == "__main__": main() |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
#!/usr/bin/env python import clang.cindex import sys import os import logging import argparse import fnmatch from DotGenerator import * index = clang.cindex.Index.create() dotGenerator = DotGenerator() def findFilesInDir(rootDir, patterns): """ Searches for files in rootDir which file names mathes the given pattern. Returns a list of file paths of found files""" foundFiles = [] for root, dirs, files in os.walk(rootDir): for p in patterns: for filename in fnmatch.filter(files, p): foundFiles.append(os.path.join(root, filename)) return foundFiles def processClassField(cursor): """ Returns the name and the type of the given class field. The cursor must be of kind CursorKind.FIELD_DECL""" type = None fieldChilds = list(cursor.get_children()) if len(fieldChilds) == 0: # if there are not cursorchildren, the type is some primitive datatype type = cursor.type.spelling else: # if there are cursorchildren, the type is some non-primitive datatype (a class or class template) for cc in fieldChilds: if cc.kind == clang.cindex.CursorKind.TEMPLATE_REF: type = cc.spelling elif cc.kind == clang.cindex.CursorKind.TYPE_REF: type = cursor.type.spelling name = cursor.spelling return name, type def processClassMemberDeclaration(umlClass, cursor): """ Processes a cursor corresponding to a class member declaration and appends the extracted information to the given umlClass """ if cursor.kind == clang.cindex.CursorKind.CXX_BASE_SPECIFIER: for baseClass in cursor.get_children(): if baseClass.kind == clang.cindex.CursorKind.TEMPLATE_REF: umlClass.parents.append(baseClass.spelling) elif baseClass.kind == clang.cindex.CursorKind.TYPE_REF: umlClass.parents.append(baseClass.type.spelling) elif cursor.kind == clang.cindex.CursorKind.FIELD_DECL: # non static data member name, type = processClassField(cursor) if name is not None and type is not None: # clang < 3.5: needs patched cindex.py to have # clang.cindex.AccessSpecifier available: # https://gitorious.org/clang-mirror/clang-mirror/commit/e3d4e7c9a45ed9ad4645e4dc9f4d3b4109389cb7 if cursor.access_specifier == clang.cindex.AccessSpecifier.PUBLIC: umlClass.publicFields.append((name, type)) elif cursor.access_specifier == clang.cindex.AccessSpecifier.PRIVATE: umlClass.privateFields.append((name, type)) elif cursor.access_specifier == clang.cindex.AccessSpecifier.PROTECTED: umlClass.protectedFields.append((name, type)) elif cursor.kind == clang.cindex.CursorKind.CXX_METHOD: try: returnType, argumentTypes = cursor.type.spelling.split(' ', 1) if cursor.access_specifier == clang.cindex.AccessSpecifier.PUBLIC: umlClass.publicMethods.append((returnType, cursor.spelling, argumentTypes)) elif cursor.access_specifier == clang.cindex.AccessSpecifier.PRIVATE: umlClass.privateMethods.append((returnType, cursor.spelling, argumentTypes)) elif cursor.access_specifier == clang.cindex.AccessSpecifier.PROTECTED: umlClass.protectedMethods.append((returnType, cursor.spelling, argumentTypes)) except: logging.error("Invalid CXX_METHOD declaration! " + str(cursor.type.spelling)) elif cursor.kind == clang.cindex.CursorKind.FUNCTION_TEMPLATE: returnType, argumentTypes = cursor.type.spelling.split(' ', 1) if cursor.access_specifier == clang.cindex.AccessSpecifier.PUBLIC: umlClass.publicMethods.append((returnType, cursor.spelling, argumentTypes)) elif cursor.access_specifier == clang.cindex.AccessSpecifier.PRIVATE: umlClass.privateMethods.append((returnType, cursor.spelling, argumentTypes)) elif cursor.access_specifier == clang.cindex.AccessSpecifier.PROTECTED: umlClass.protectedMethods.append((returnType, cursor.spelling, argumentTypes)) def processClass(cursor, inclusionConfig): """ Processes an ast node that is a class. """ umlClass = UmlClass() # umlClass is the datastructure for the DotGenerator # that stores the necessary information about a single class. # We extract this information from the clang ast hereafter ... if cursor.kind == clang.cindex.CursorKind.CLASS_TEMPLATE: # process declarations like: # template <typename T> class MyClass umlClass.fqn = cursor.spelling else: # process declarations like: # class MyClass ... # struct MyStruct ... umlClass.fqn = cursor.type.spelling # the fully qualified name import re if (inclusionConfig['excludeClasses'] and re.match(inclusionConfig['excludeClasses'], umlClass.fqn)): return if (inclusionConfig['includeClasses'] and not re.match(inclusionConfig['includeClasses'], umlClass.fqn)): return for c in cursor.get_children(): # process member variables and methods declarations processClassMemberDeclaration(umlClass, c) dotGenerator.addClass(umlClass) def traverseAst(cursor, inclusionConfig): if (cursor.kind == clang.cindex.CursorKind.CLASS_DECL or cursor.kind == clang.cindex.CursorKind.STRUCT_DECL or cursor.kind == clang.cindex.CursorKind.CLASS_TEMPLATE): # if the current cursor is a class, class template or struct declaration, # we process it further ... processClass(cursor, inclusionConfig) for child_node in cursor.get_children(): traverseAst(child_node, inclusionConfig) def parseTranslationUnit(filePath, includeDirs, inclusionConfig): clangArgs = ['-x', 'c++'] + ['-I' + includeDir for includeDir in includeDirs] tu = index.parse(filePath, args=clangArgs, options=clang.cindex.TranslationUnit.PARSE_SKIP_FUNCTION_BODIES) for diagnostic in tu.diagnostics: logging.debug(diagnostic) logging.info('Translation unit:' + tu.spelling + "\n") traverseAst(tu.cursor, inclusionConfig) if __name__ == "__main__": parser = argparse.ArgumentParser(description="CodeDependencyVisualizer (CDV)") parser.add_argument('-d', required=True, help="directory with source files to parse (searches recusively)") parser.add_argument('-o', '--outFile', default='uml.dot', help="output file name / name of generated dot file") parser.add_argument('-u', '--withUnusedHeaders', help="parse unused header files (slow)") parser.add_argument('-a', '--associations', action="store_true", help="draw class member assiciations") parser.add_argument('-i', '--inheritances', action="store_true", help="draw class inheritances") parser.add_argument('-p', '--privMembers', action="store_true", help="show private members") parser.add_argument('-t', '--protMembers', action="store_true", help="show protected members") parser.add_argument('-P', '--pubMembers', action="store_true", help="show public members") parser.add_argument('-I', '--includeDirs', help="additional search path(s) for include files (seperated by space)", nargs='+') parser.add_argument('-v', '--verbose', action="store_true", help="print verbose information for debugging purposes") parser.add_argument('--excludeClasses', help="classes matching this pattern will be excluded") parser.add_argument('--includeClasses', help="only classes matching this pattern will be included") args = vars(parser.parse_args(sys.argv[1:])) filesToParsePatterns = ['*.cpp', '*.cxx', '*.c', '*.cc'] if args['withUnusedHeaders']: filesToParsePatterns += ['*.h', '*.hxx', '*.hpp'] filesToParse = findFilesInDir(args['d'], filesToParsePatterns) subdirectories = [x[0] for x in os.walk(args['d'])] loggingFormat = "%(levelname)s - %(module)s: %(message)s" logging.basicConfig(format=loggingFormat, level=logging.INFO) if args['verbose']: logging.basicConfig(format=loggingFormat, level=logging.DEBUG) logging.info("found " + str(len(filesToParse)) + " source files.") for sourceFile in filesToParse: logging.info("parsing file " + sourceFile) parseTranslationUnit(sourceFile, args['includeDirs'], { 'excludeClasses': args['excludeClasses'], 'includeClasses': args['includeClasses']}) dotGenerator.setDrawAssociations(args['associations']) dotGenerator.setDrawInheritances(args['inheritances']) dotGenerator.setShowPrivMethods(args['privMembers']) dotGenerator.setShowProtMethods(args['protMembers']) dotGenerator.setShowPubMethods(args['pubMembers']) dotfileName = args['outFile'] logging.info("generating dotfile " + dotfileName) with open(dotfileName, 'w') as dotfile: dotfile.write(dotGenerator.generate()) |