Commit e69fcde6 authored by YONG-LIN SU's avatar YONG-LIN SU

20220613Allen新增透過matplot顯示車牌辨識結果方法

parent 0f93fd8f
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "64da5475",
"metadata": {},
"outputs": [],
"source": [
"import cv2\n",
"import queue\n",
"%matplotlib\n",
"import matplotlib.pyplot as plt\n",
"\n",
"import numpy as np\n",
"import time"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ff25adac",
"metadata": {},
"outputs": [],
"source": [
"class ResultInfo(object):\n",
" def __init__(self,track_id, plate,vechile_img, plate_img):\n",
" self.track_id = track_id\n",
" self.plate = plate\n",
" self.vechile_img = vechile_img\n",
" self.plate_img = plate_img"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b55297ef",
"metadata": {},
"outputs": [],
"source": [
"# 初始化 plt 圖表\n",
"# to run GUI event loop\n",
"# plt.ion()\n",
"fig, ax_list = plt.subplots(5, 2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9454cb28",
"metadata": {},
"outputs": [],
"source": [
"ax_cache_imgs = []\n",
"ax_cache_backgrounds = []\n",
"ax_list = ax_list.ravel()\n",
"fake_img = np.zeros((320,320))\n",
"for i in range(len(ax_list)):\n",
" img = ax_list[i].imshow(fake_img, vmin=-1, vmax=1, interpolation=\"None\", cmap=\"RdBu\")\n",
" ax_cache_imgs.append(img)\n",
" \n",
" axbackground = fig.canvas.copy_from_bbox(ax_list[i].bbox)\n",
" ax_cache_backgrounds.append(axbackground)\n",
" \n",
"fig.canvas.draw() # note that the first draw comes before setting data \n",
"plt.show(block=False)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "81e6eff6",
"metadata": {},
"outputs": [],
"source": [
"begin_time = time.time()\n",
"for i in range(10):\n",
" if(i%2== 0):\n",
" stime = time.time()\n",
" ax_cache_imgs[i].set_array(img1)\n",
" print(time.time() - stime)\n",
" else:\n",
" stime = time.time()\n",
" ax_cache_imgs[i].set_array(img1)\n",
" print(time.time() - stime)\n",
" \n",
"# restore background\n",
" fig.canvas.restore_region(ax_cache_backgrounds[i])\n",
"# fig.canvas.draw()\n",
" fig.canvas.flush_events()\n",
"print(\"done spend \", time.time() - begin_time)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "08bdf567",
"metadata": {},
"outputs": [],
"source": [
"img1 = cv2.imread(\"/home/aaeon/1Car1Plate.jpg\")\n",
"img2 = cv2.imread(\"/home/aaeon/1Plate.jpg\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "70b2ca7d",
"metadata": {},
"outputs": [],
"source": [
"for i in range(9):\n",
" title=\"title\"+str(i+1)\n",
" #行,列,索引\n",
" plt.subplot(3,3,i+1)\n",
" plt.imshow(img)\n",
" plt.title(title,fontsize=8)\n",
" plt.xticks([])\n",
" plt.yticks([])\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "93b2088c",
"metadata": {},
"outputs": [],
"source": [
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "12e0dd38",
"metadata": {},
"outputs": [],
"source": [
"x = np.linspace(0, 10, 100)\n",
"y = np.cos(x)\n",
"\n",
"plt.ion()\n",
"\n",
"figure, ax = plt.subplots(figsize=(8,6))\n",
"line1, = ax.plot(x, y)\n",
"\n",
"plt.title(\"Dynamic Plot of sinx\",fontsize=25)\n",
"\n",
"plt.xlabel(\"X\",fontsize=18)\n",
"plt.ylabel(\"sinX\",fontsize=18)\n",
"\n",
"for p in range(100):\n",
" updated_y = np.cos(x-0.05*p)\n",
" \n",
" line1.set_xdata(x)\n",
" line1.set_ydata(updated_y)\n",
" \n",
" figure.canvas.draw()\n",
" \n",
" figure.canvas.flush_events()\n",
" time.sleep(0.1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7572b4be",
"metadata": {},
"outputs": [],
"source": [
"x = np.linspace(0, 10, 100)\n",
"y = np.cos(x)\n",
"\n",
"fig = plt.figure()\n",
"\n",
"for p in range(50):\n",
" p=3\n",
" updated_x=x+p\n",
" updated_y=np.cos(x)\n",
" plt.plot(updated_x,updated_y)\n",
" plt.draw() \n",
" x=updated_x\n",
" y=updated_y\n",
" plt.pause(0.2)\n",
" fig.clear()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8f7ed71c",
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"from matplotlib.animation import FuncAnimation\n",
"\n",
"im = plt.imshow(np.random.randn(10,10))\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "834a4c32",
"metadata": {},
"outputs": [],
"source": [
"def update(i):\n",
" A = np.random.randn(10,10)\n",
" im.set_array(A)\n",
" return im, text\n",
"\n",
"ani = FuncAnimation(plt.gcf(), update, frames=range(100), interval=5, blit=False)\n",
"\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1a29f44a",
"metadata": {},
"outputs": [],
"source": [
"def live_update_demo(blit = False):\n",
" x = np.linspace(0,50., num=100)\n",
" X,Y = np.meshgrid(x,x)\n",
" fig = plt.figure()\n",
" ax1 = fig.add_subplot(2, 1, 1)\n",
" ax2 = fig.add_subplot(2, 1, 2)\n",
"\n",
" img = ax1.imshow(X, vmin=-1, vmax=1, interpolation=\"None\", cmap=\"RdBu\")\n",
"\n",
"\n",
" line, = ax2.plot([], lw=3)\n",
" text = ax2.text(0.8,0.5, \"\")\n",
"\n",
" ax2.set_xlim(x.min(), x.max())\n",
" ax2.set_ylim([-1.1, 1.1])\n",
"\n",
" fig.canvas.draw() # note that the first draw comes before setting data \n",
"\n",
"\n",
" if blit:\n",
" # cache the background\n",
" axbackground = fig.canvas.copy_from_bbox(ax1.bbox)\n",
" ax2background = fig.canvas.copy_from_bbox(ax2.bbox)\n",
"\n",
" plt.show(block=False)\n",
"\n",
"\n",
" t_start = time.time()\n",
" k=0.\n",
"\n",
" for i in np.arange(1000):\n",
" img.set_data(np.sin(X/3.+k)*np.cos(Y/3.+k))\n",
" line.set_data(x, np.sin(x/3.+k))\n",
" tx = 'Mean Frame Rate:\\n {fps:.3f}FPS'.format(fps= ((i+1) / (time.time() - t_start)) ) \n",
" text.set_text(tx)\n",
" #print tx\n",
" k+=0.11\n",
" if blit:\n",
" # restore background\n",
" fig.canvas.restore_region(axbackground)\n",
" fig.canvas.restore_region(ax2background)\n",
"\n",
" # redraw just the points\n",
" ax1.draw_artist(img)\n",
" ax2.draw_artist(line)\n",
" ax2.draw_artist(text)\n",
"\n",
" # fill in the axes rectangle\n",
" fig.canvas.blit(ax1.bbox)\n",
" fig.canvas.blit(ax2.bbox)\n",
"\n",
" # in this post http://bastibe.de/2013-05-30-speeding-up-matplotlib.html\n",
" # it is mentionned that blit causes strong memory leakage. \n",
" # however, I did not observe that.\n",
"\n",
" else:\n",
" # redraw everything\n",
" fig.canvas.draw()\n",
"\n",
" fig.canvas.flush_events()\n",
" #alternatively you could use\n",
" #plt.pause(0.000000000001) \n",
" # however plt.pause calls canvas.draw(), as can be read here:\n",
" #http://bastibe.de/2013-05-30-speeding-up-matplotlib.html\n",
"\n",
"\n",
"live_update_demo(True) # 175 fps"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5519f5d1",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.9"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
...@@ -79,7 +79,7 @@ class TrtRetinaPlateThread(threading.Thread): ...@@ -79,7 +79,7 @@ class TrtRetinaPlateThread(threading.Thread):
loc = boxes[0] loc = boxes[0]
crop_img = info.img[loc[1]:loc[3],loc[0]:loc[2]] crop_img = info.img[loc[1]:loc[3],loc[0]:loc[2]]
# 過濾物件 # 過濾物件
plateInfo = PlateInfo(info.track_id, crop_img) plateInfo = PlateInfo(info.track_id, info.img ,crop_img)
self.plates_q.put(plateInfo) self.plates_q.put(plateInfo)
# with self.condition: # with self.condition:
# s_img, s_boxes, s_confs, s_lands = info.img, boxes, confs, lands # s_img, s_boxes, s_confs, s_lands = info.img, boxes, confs, lands
...@@ -139,13 +139,17 @@ class TrtCTCOCRThread(threading.Thread): ...@@ -139,13 +139,17 @@ class TrtCTCOCRThread(threading.Thread):
if(not isinstance(info, PlateInfo)): if(not isinstance(info, PlateInfo)):
continue continue
if(info.img is None): if(info.plate_img is None):
continue continue
# stime = time.time() # stime = time.time()
plate = self.trt_ocr.recognition(info.img) try:
plate = self.trt_ocr.recognition(info.plate_img)
except Exception as e:
print(e)
plate = ""
# print("Resnet32 CTC OCR 480*16 shared memory inference time", time.time() - stime) # print("Resnet32 CTC OCR 480*16 shared memory inference time", time.time() - stime)
resultInfo = ResultInfo(info.track_id, plate) resultInfo = ResultInfo(info.track_id, plate, info.vechile_img, info.plate_img)
self.results_q.put(resultInfo) self.results_q.put(resultInfo)
# with self.condition: # with self.condition:
# s_img, s_boxes, s_confs, s_lands = img, boxes, confs, lands # s_img, s_boxes, s_confs, s_lands = img, boxes, confs, lands
...@@ -164,14 +168,17 @@ class VehicleInfo(object): ...@@ -164,14 +168,17 @@ class VehicleInfo(object):
self.img = img self.img = img
class PlateInfo(object): class PlateInfo(object):
def __init__(self,track_id, img): def __init__(self,track_id, vechile_img, plate_img):
self.track_id = track_id self.track_id = track_id
self.img = img self.vechile_img = vechile_img
self.plate_img = plate_img
class ResultInfo(object): class ResultInfo(object):
def __init__(self,track_id, plate): def __init__(self,track_id, plate,vechile_img, plate_img):
self.track_id = track_id self.track_id = track_id
self.plate = plate self.plate = plate
self.vechile_img = vechile_img
self.plate_img = plate_img
class EZLPR(object): class EZLPR(object):
...@@ -193,7 +200,7 @@ class EZLPR(object): ...@@ -193,7 +200,7 @@ class EZLPR(object):
def out(self): def out(self):
while not self.resultsQueue.empty(): while not self.resultsQueue.empty():
resultInfo = self.resultsQueue.get() resultInfo = self.resultsQueue.get()
yield resultInfo.track_id,resultInfo.plate yield resultInfo.track_id,resultInfo.plate, resultInfo.vechile_img, resultInfo.plate_img
def __del__(self): def __del__(self):
self.trtRetinaPlateThread.stop() self.trtRetinaPlateThread.stop()
......
...@@ -59,7 +59,7 @@ cam.start() ...@@ -59,7 +59,7 @@ cam.start()
clsName={'2.0':'car','0.0':'person','3.0':'motorbike','5.0':'bus','7.0':'truck'} clsName={'2.0':'car','0.0':'person','3.0':'motorbike','5.0':'bus','7.0':'truck'}
LPR_target=['2.0','3.0','5.0','7.0'] LPR_target=['2.0','3.0','5.0','7.0']
FPS=list() FPS=list()
is_display=False; # 是否要畫面顯示的 flag is_display=True; # 是否要畫面顯示的 flag
''' '''
...@@ -130,8 +130,9 @@ try: ...@@ -130,8 +130,9 @@ try:
OutputLPR_span,stime=time_span(stime) # ! OutputLPR_span,stime=time_span(stime) # !
CT.GetDisposeBuffer() CT.GetDisposeBuffer()
#for obj in CT.GetDisposeBuffer(): for obj in CT.GetDisposeBuffer():
# InfluxWriter.put(obj) pass
# InfluxWriter.put(obj)
FPS.append(1/(time.time()-staic_stime)) FPS.append(1/(time.time()-staic_stime))
if is_display: if is_display:
......
This diff is collapsed.
...@@ -15,7 +15,7 @@ class Camera(object): ...@@ -15,7 +15,7 @@ class Camera(object):
self.height = height self.height = height
self.framerate = framerate self.framerate = framerate
self.encoder = encoder self.encoder = encoder
self.use_gstr = False self.use_gstr = True
self.__thread = Thread(target=self.__job) self.__thread = Thread(target=self.__job)
self.resultQueue = Queue(maxsize=maxsize) self.resultQueue = Queue(maxsize=maxsize)
def start(self): def start(self):
...@@ -86,13 +86,14 @@ class Camera(object): ...@@ -86,13 +86,14 @@ class Camera(object):
if self.encoder=="h265": if self.encoder=="h265":
print("h265") print("h265")
return ( return (
f'rtspsrc location={source} ! ' + f'rtspsrc location={source} protocols=tcp ! ' +
# 'watchdog timeout=10000 !'+
'rtph265depay ! h265parse ! nvv4l2decoder ! nvvidconv ! '+ 'rtph265depay ! h265parse ! nvv4l2decoder ! nvvidconv ! '+
'video/x-raw,format=BGRx ! videoconvert ! video/x-raw,format=BGR ! appsink' 'video/x-raw,format=BGRx ! videoconvert ! video/x-raw,format=BGR ! appsink'
) )
elif self.encoder=="h264": elif self.encoder=="h264":
print("h264") print("h264")
gst_str = ('rtspsrc location={} latency={} ! ' gst_str = ('rtspsrc location={} latency={} protocols=tcp ! '
'rtph264depay ! h264parse ! omxh264dec ! ' 'rtph264depay ! h264parse ! omxh264dec ! '
'nvvidconv ! ' 'nvvidconv ! '
'video/x-raw, width=(int){}, height=(int){}, ' 'video/x-raw, width=(int){}, height=(int){}, '
......
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "59315357",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Using matplotlib backend: TkAgg\n"
]
}
],
"source": [
"import cv2\n",
"import queue\n",
"%matplotlib\n",
"import matplotlib.pyplot as plt\n",
"\n",
"import numpy as np\n",
"import time"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "bf058820",
"metadata": {},
"outputs": [],
"source": [
"class ResultInfo(object):\n",
" def __init__(self,track_id, plate,vechile_img, plate_img):\n",
" self.track_id = track_id\n",
" self.plate = plate\n",
" self.vechile_img = vechile_img\n",
" self.plate_img = plate_img"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "fef5c52d",
"metadata": {},
"outputs": [],
"source": [
"# 初始化 plt 圖表\n",
"# to run GUI event loop\n",
"# plt.ion()\n",
"fig, ax_list = plt.subplots(5, 2)"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "aa00acc6",
"metadata": {},
"outputs": [],
"source": [
"ax_cache_imgs = []\n",
"ax_cache_backgrounds = []\n",
"ax_list = ax_list.ravel()\n",
"fake_img = np.zeros((320,320))\n",
"for i in range(len(ax_list)):\n",
" img = ax_list[i].imshow(fake_img, vmin=-1, vmax=1, interpolation=\"None\", cmap=\"RdBu\")\n",
" ax_cache_imgs.append(img)\n",
" \n",
" ax_list[i].axis('off')\n",
" \n",
" axbackground = fig.canvas.copy_from_bbox(ax_list[i].bbox)\n",
" ax_cache_backgrounds.append(axbackground)\n",
" \n",
"fig.canvas.draw() # note that the first draw comes before setting data \n",
"plt.show(block=False)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "e5988e1e",
"metadata": {},
"outputs": [],
"source": [
"ax_list[i].title.set_text(\"test\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ab6de658",
"metadata": {},
"outputs": [],
"source": [
"begin_time = time.time()\n",
"for i in range(5):\n",
" if(i%2== 0):\n",
" stime = time.time()\n",
" ax_cache_imgs[i].set_array(img2)\n",
" print(time.time() - stime)\n",
" else:\n",
" stime = time.time()\n",
" ax_cache_imgs[i].set_array(img1)\n",
" print(time.time() - stime)\n",
" \n",
"# restore background\n",
" fig.canvas.restore_region(ax_cache_backgrounds[i])\n",
"# fig.canvas.draw()\n",
"fig.canvas.flush_events()\n",
"print(\"done spend \", time.time() - begin_time)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f7b7d10f",
"metadata": {},
"outputs": [],
"source": [
"img1 = cv2.imread(\"/home/aaeon/1Car1Plate.jpg\")\n",
"img2 = cv2.imread(\"/home/aaeon/1Plate.jpg\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "94199440",
"metadata": {},
"outputs": [],
"source": [
"for i in range(9):\n",
" title=\"title\"+str(i+1)\n",
" #行,列,索引\n",
" plt.subplot(3,3,i+1)\n",
" plt.imshow(img)\n",
" plt.title(title,fontsize=8)\n",
" plt.xticks([])\n",
" plt.yticks([])\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9b90ab72",
"metadata": {},
"outputs": [],
"source": [
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "662b6289",
"metadata": {},
"outputs": [],
"source": [
"x = np.linspace(0, 10, 100)\n",
"y = np.cos(x)\n",
"\n",
"plt.ion()\n",
"\n",
"figure, ax = plt.subplots(figsize=(8,6))\n",
"line1, = ax.plot(x, y)\n",
"\n",
"plt.title(\"Dynamic Plot of sinx\",fontsize=25)\n",
"\n",
"plt.xlabel(\"X\",fontsize=18)\n",
"plt.ylabel(\"sinX\",fontsize=18)\n",
"\n",
"for p in range(100):\n",
" updated_y = np.cos(x-0.05*p)\n",
" \n",
" line1.set_xdata(x)\n",
" line1.set_ydata(updated_y)\n",
" \n",
" figure.canvas.draw()\n",
" \n",
" figure.canvas.flush_events()\n",
" time.sleep(0.1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3d6dc092",
"metadata": {},
"outputs": [],
"source": [
"x = np.linspace(0, 10, 100)\n",
"y = np.cos(x)\n",
"\n",
"fig = plt.figure()\n",
"\n",
"for p in range(50):\n",
" p=3\n",
" updated_x=x+p\n",
" updated_y=np.cos(x)\n",
" plt.plot(updated_x,updated_y)\n",
" plt.draw() \n",
" x=updated_x\n",
" y=updated_y\n",
" plt.pause(0.2)\n",
" fig.clear()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2aa98e09",
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"from matplotlib.animation import FuncAnimation\n",
"\n",
"im = plt.imshow(np.random.randn(10,10))\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5c679420",
"metadata": {},
"outputs": [],
"source": [
"def update(i):\n",
" A = np.random.randn(10,10)\n",
" im.set_array(A)\n",
" return im, text\n",
"\n",
"ani = FuncAnimation(plt.gcf(), update, frames=range(100), interval=5, blit=False)\n",
"\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d21dc12f",
"metadata": {},
"outputs": [],
"source": [
"def live_update_demo(blit = False):\n",
" x = np.linspace(0,50., num=100)\n",
" X,Y = np.meshgrid(x,x)\n",
" fig = plt.figure()\n",
" ax1 = fig.add_subplot(2, 1, 1)\n",
" ax2 = fig.add_subplot(2, 1, 2)\n",
"\n",
" img = ax1.imshow(X, vmin=-1, vmax=1, interpolation=\"None\", cmap=\"RdBu\")\n",
"\n",
"\n",
" line, = ax2.plot([], lw=3)\n",
" text = ax2.text(0.8,0.5, \"\")\n",
"\n",
" ax2.set_xlim(x.min(), x.max())\n",
" ax2.set_ylim([-1.1, 1.1])\n",
"\n",
" fig.canvas.draw() # note that the first draw comes before setting data \n",
"\n",
"\n",
" if blit:\n",
" # cache the background\n",
" axbackground = fig.canvas.copy_from_bbox(ax1.bbox)\n",
" ax2background = fig.canvas.copy_from_bbox(ax2.bbox)\n",
"\n",
" plt.show(block=False)\n",
"\n",
"\n",
" t_start = time.time()\n",
" k=0.\n",
"\n",
" for i in np.arange(1000):\n",
" img.set_data(np.sin(X/3.+k)*np.cos(Y/3.+k))\n",
" line.set_data(x, np.sin(x/3.+k))\n",
" tx = 'Mean Frame Rate:\\n {fps:.3f}FPS'.format(fps= ((i+1) / (time.time() - t_start)) ) \n",
" text.set_text(tx)\n",
" #print tx\n",
" k+=0.11\n",
" if blit:\n",
" # restore background\n",
" fig.canvas.restore_region(axbackground)\n",
" fig.canvas.restore_region(ax2background)\n",
"\n",
" # redraw just the points\n",
" ax1.draw_artist(img)\n",
" ax2.draw_artist(line)\n",
" ax2.draw_artist(text)\n",
"\n",
" # fill in the axes rectangle\n",
" fig.canvas.blit(ax1.bbox)\n",
" fig.canvas.blit(ax2.bbox)\n",
"\n",
" # in this post http://bastibe.de/2013-05-30-speeding-up-matplotlib.html\n",
" # it is mentionned that blit causes strong memory leakage. \n",
" # however, I did not observe that.\n",
"\n",
" else:\n",
" # redraw everything\n",
" fig.canvas.draw()\n",
"\n",
" fig.canvas.flush_events()\n",
" #alternatively you could use\n",
" #plt.pause(0.000000000001) \n",
" # however plt.pause calls canvas.draw(), as can be read here:\n",
" #http://bastibe.de/2013-05-30-speeding-up-matplotlib.html\n",
"\n",
"\n",
"live_update_demo(True) # 175 fps"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ce02ec28",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.9"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment