φυβλαςのβλογ
phyblas的博客



opencv-python เบื้องต้น บทที่ ๒: การอ่านเขียนไฟล์ภาพ
เขียนเมื่อ 2020/06/28 18:24
แก้ไขล่าสุด 2024/02/22 10:27

ต่อจาก บทที่ ๑

ในบทนี้จะแนะนำการอ่านไฟล์ภาพเข้ามาเป็นอาเรย์ในไพธอนด้วย cv2.imread() และเขียนภาพลงไฟล์ด้วย cv2.imwrite() รวมถึงเรื่องระบบสีและการนำภาพมาแสดงโดย matplotlib




การอ่านภาพจากไฟล์มาเป็นอาเรย์

ฟังก์ชันสำหรับอ่านไฟล์รูปภาพใน opencv คือ cv2.imread() ใช้อ่านภาพจากไฟล์เข้ามาเป็นอาเรย์ของ numpy

เกี่ยวกับการใช้งานอาเรย์ในรายละเอียดนั้นจะไม่เน้นอธิบายในนี้มาก อาจอ่านเพิ่มเติมได้ใน เนื้อหา numpy & matplotlib เบื้องต้น โดยเฉพาะในบทที่ ๔: การตัดแต่งแก้ไขอาเรย์

ในที่นี้ขอยกตัวอย่างการอ่านไฟล์รูปภาพโดยใช้ภาพนี้เป็นตัวอย่าง เซฟไปใช้เพื่อลองทำตามได้

miku02c01.jpg

วิธีการใช้คือให้ใส่ชื่อไฟล์รูปภาพที่ต้องการอ่านลงไป ก็จะได้อาเรย์ของภาพมา
import cv2
# numpy กับ matplotlib เองก็ใช้ตลอดด้วย แนะนำให้ import ไปด้วยทุกครั้ง
import numpy as np
import matplotlib.pyplot as plt

rup = cv2.imread('miku02c01.jpg')
print(type(rup)) # ชนิดออบเจ็กต์ ได้ <class 'numpy.ndarray'>
print(rup.shape) # รูปร่างอาเรย์ ได้ (450, 600, 3)
print(rup.dtype) # ชนิดข้อมูล ได้ uint8
print(rup.min()) # ค่าต่ำสุด ได้ 0
print(rup.max()) # ค่าสูงสุด ได้ 255

ภาพที่อ่านขึ้นมาได้จะอยู่ในรูปของอาเรย์ ๓ มิติ ซึ่งมีความหมายดังนี้
  • มิติที่ 0: ความสูง มีขนาดเท่ากับจำนวนพิกเซลแนวตั้ง
  • มิติที่ 1: ความกว้าง มีขนาดเท่ากับจำนวนพิกเซลแนวนอน
  • มิติที่ 2: มีขนาดเป็น 3 แสดงถึงสี ๓ สี (น้ำเงิน, เขียว, แดง)
โดย dtype (ชนิดของข้อมูลภายในอาเรย์) จะเป็น unit8 ซึ่งเป็นค่าจำนวนเต็มที่อยู่ได้แค่ในช่วง 0 ถึง 255 เท่านั้น

ข้อควรระวังคือ ๓ สีใน opencv นั้นจะเรียงค่อนข้างแปลกกว่าที่อื่น คือเป็น [น้ำเงิน, เขียว, แดง] (BGR) ในขณะที่สากลส่วนใหญ่จะเรียงเป็น [แดง, เขียว, น้ำเงิน] (RGB)

และการที่ข้อมูลเป็นอาเรย์ ทำให้การเข้าถึงแนวตั้งมาก่อนแนวนอน คือมิติที่ 0 (มิติแรก) แทนแนวตั้ง คือตามแกน y และมิติถัดมาจึงแสดงแนวนอน แกน x ดังนั้นจึงเป็น (y,x) ไม่ใช่ (x,y) ตรงนี้เป็นเรื่องที่อาจทำให้สับสนเผลอเขียนสลับกันได้ง่าย ต้องทำความเคยชินให้ดี

ในตัวอย่างนี้ขนาดของอาเรย์เป็น (450, 600, 3) จึงหมายถึงสูง ๔๕๐ พิกเซล กว้าง ๖๐๐ พิกเซล มี ๓ สี




การแปลงชนิดของข้อมูล

ดังที่ได้กล่าวถึงไปในบทนำแล้วว่าเรื่องชนิดของข้อมูลเป็นสิ่งที่ต้องระวังเป็นพิเศษเวลาใช้ opencv

เวลาเปิดไฟล์ขึ้นมาโดยใช้ cv2.imread() จะได้ชนิดข้อมูลเป็น uint8 หากต้องการชนิดอื่นก็ค่อยนำมาแปลงอีกทีได้

วิธีการแปลงชนิดข้อมูลภายในอาเรย์ของ numpy มีอยู่หลายวิธี เช่นถ้าต้องการเปลี่ยนเป็น float32 อาจเขียนได้แบบนี้
rup = rup.astype(np.float32)
rup = np.float32(rup)
rup = np.array(rup,dtype=np.float32)
rup = rup.astype('float32')
rup = np.array(rup,dtype='float32')




ภาพสีและขาวดำ

ภาพที่อ่านขึ้นมาโดยคำสั่ง cv2.imread() นี้หากแค่ใส่ชื่อไฟล์ลงไปโดยไม่กำหนดอะไรเลยก็จะอ่านภาพมาเป็นอาเรย์ของสี ๓ สีเสมอ แม้ว่าจะเป็นภาพขาวดำก็ตาม

หากต้องการอ่านภาพแบบอื่นให้กำหนดสิ่งที่เรียกว่า "แฟล็ก" (flag) โดยเติมเป็นพารามิเตอร์ตัวที่ ๒ ลงไปถัดจากชื่อไฟล์

แฟล็กที่ใส่ได้คือ cv2.IMREAD_GRAYSCALE สำหรับอ่านภาพขาวดำ และ cv2.IMREAD_COLOR สำหรับอ่านภาพเป็นภาพสี

ที่จริงแล้วค่าพวกนี้เป็นแค่ตัวเลขธรรมดา เช่น cv2.IMREAD_GRAYSCALE จริงๆคือ 0 ส่วน cv2.IMREAD_COLOR นั้นจริงๆคือ 1
print(cv2.IMREAD_GRAYSCALE) # ได้ 0
print(cv2.IMREAD_COLOR) # ได้ 1

หากไม่ได้ใส่ ค่าตั้งต้นคือ 1 คือ cv2.IMREAD_COLOR อยู่แล้ว จึงเป็นภาพสี ดังนั้นหากต้องการอ่านภาพขาวดำให้ใส่ cv2.IMREAD_GRAYSCALE หรือจะใส่เลข 0 ไปโดยตรงก็ได้

ตัวอย่าง
rup = cv2.imread('miku02c01.jpg',cv2.IMREAD_UNCHANGED)
print(rup.shape) # ได้ (450, 600, 3)

จะเขียน cv2.IMREAD_GRAYSCALE หรือ 0 ก็ให้ผลเหมือนกัน แต่การใส่แฟล็กในรูปตัวแปรแฟล็กแบบนี้แทนที่จะใส่เป็นตัวเลข 0 โดยตรงจะทำให้เห็นภาพชัดกว่า เพราะไม่ต้องมาจำว่าภาพขาวดำคือ 0 ภาพสีคือ 1 แบบนี้ ดังนั้นโดยทั่วไปแนะนำให้ใส่ cv2.IMREAD_GRAYSCALE มากกว่าที่จะใส่เลข 0 ไปเฉยๆ แม้จะเขียนยาวกว่าก็ตาม

นอกจากนี้ยังมี cv2.IMREAD_UNCHANGED (ค่าเป็น -1) ซึ่งจะดูว่าภาพนั้นเป็นภาพแบบไหน ถ้าเป็นขาวดำก็จะอ่านเป็นขาวดำโดยอัตโนมัติ ถ้ามีสีก็จะอ่านเป็นสี

ตัวอย่างเช่น สมมุติว่ามีภาพนี้ ซึ่งเป็นภาพขาวดำ

miku02c02.jpg

ถ้าอ่านโดยไม่ใส่แฟล็กก็จะได้เป็นอาเรย์ ๓​ มิติ แต่ถ้าใส่ cv2.IMREAD_UNCHANGED หรือ cv2.IMREAD_GRAYSCALE จึงจะได้เป็นภาพขาวดำ
rup = cv2.imread('miku02c02.jpg')
print(rup.shape) # ได้ (450, 600, 3)

rup = cv2.imread('miku02c02.jpg',cv2.IMREAD_UNCHANGED)
print(rup.shape) # ได้ (450, 600)

แต่หากเป็นภาพสีอยู่แล้ว ใส่ cv2.IMREAD_UNCHANGED ก็จะเป็นภาพสีเหมือนกับใส่ cv2.IMREAD_COLOR หรือไม่ใส่อะไร

ดังนั้นหากไม่รู้ว่าเป็นภาพสีหรือภาพขาวดำ แต่ต้องการให้อ่านในแบบนั้นอย่างที่ควรเป็นก็ให้ใส่ cv2.IMREAD_UNCHANGED (หรือ -1) ไป

แฟล็ก เลข ความหมาย
cv2.IMREAD_UNCHANGED -1 เปิดขึ้นมาเป็นมีสีหรือขาวดำแล้วแต่ภาพ
cv2.IMREAD_GRAYSCALE 0 เปิดขึ้นมาเป็นภาพขาวดำ
cv2.IMREAD_COLOR 1 เปิดขึ้นมาเป็นภาพมีสี

นอกจากแฟล็ก ๓​ ตัวที่ยกมาแล้วยังมีแฟล็กอื่นๆอีกมาก ซึ่งในที่นี้จะยังไม่กล่าวถึง อาจสามารถลองดูแฟล็กที่เหลือได้โดยพิมพ์
print('\n'.join(['%s: %d'%(x,getattr(cv2,x)) for x in dir(cv2) if 'IMREAD' in x]))




แสดงภาพด้วย matplotlib

opencv เองก็มีฟังก์ชันที่สร้างหน้าต่าง GUI ในการดูภาพ แต่โดยทั่วไปสามารถใช้ matplotlib แทนได้ ดังนั้นในที่นี้จะยังไม่กล่าวถึง เพราะจุดประสงค์หลักคือจะมุ่งไปที่ความสามารถในการแก้ไขและวิเคราะห์ภาพโดยใช้โค้ด ส่วนการใช้ GUI นั้นอาจเขียนถึงทีหลัง

matplotlib มีฟังก์ชัน plt.imshow() ซึ่งใช้แสดงภาพได้ง่ายกว่าที่จะใช้ฟ้งก์​ชันแสดงภาพของ opencv เอง

อย่างไรก็ตาม มีข้อควรระวังดังที่ได้กล่าวไปแล้วคือระบบสีใน opencv จะเรียงเป็น [น้ำเงิน, เขียว, แดง] ในขณะที่สากลปกติรวมถึงใน matplotlib จะเรียงแบบ [แดง, เขียว, น้ำเงิน]

ดังนั้นเมื่อจะนำภาพสีมาแสดงใน matplotlib จะต้องสลับลำดับให้ถูกต้องด้วย ซึ่งก็ทำง่ายๆโดยแค่เติม [:,:,::-1] ลงไป

ตัวอย่าง อ่านภาพนี้

miku02c03.jpg

rup = cv2.imread('miku02c03.jpg')
plt.imshow(rup[:,:,::-1])
plt.show()

จะได้ภาพแบบนี้



ถ้าไม่ได้กลับสีก็จะออกมาแปลกๆแบบนี้ คือสีน้ำเงินกับแดงถูกสลับกัน ดูแปลกๆไป



ส่วนภาพขาวดำจะเป็นอาเรย์ที่มีแค่ ๒ มิติ เมื่ออ่านใน imshow() จะได้สีที่เปลี่ยนไปตาม colormap โดยค่าตั้งต้นคือสี viridis ซึ่งไล่ค่าจากต่ำไปสูงเป็น ม่วงเข้ม>เขียว>เหลือง

คราวนี้ลองอ่านภาพเดิมขึ้นมาในโหมดขาวดำแล้วใช้ imshow() จะได้แบบนี้
rup = cv2.imread('miku02c03.jpg',0)
plt.imshow(rup)
plt.colorbar(pad=0.01) # วาดแถบสีทางขวาเพื่อบอกว่าความเข้มแต่ละจุดที่เห็นเป็นเท่าไหร่ด้วย
plt.show()



เพื่อที่จะให้เห็นภาพขาวดำอย่างที่เป็นจริงๆ โดยทั่วไปควรกำหนด cmap เป็น gray
plt.imshow(rup,cmap='gray')
plt.colorbar(pad=0.01)
plt.show()



นอกจากนี้อาจใช้ Grays_r สีที่ได้จะต่างกันเล็กน้อย แต่ก็เป็นขาวดำเช่นกัน
plt.imshow(rup,cmap='Greys_r')
plt.show()



สามารถตัดมาแสดงเฉพาะบางส่วน
plt.imshow(rup[0:70,240:360],cmap='gray')
plt.show()



ข้อควรระวังอีกอย่างก็คือ เมื่อวาดแบบไร้สีใน matplotlib สีที่ปรากฏจะปรับสเกลอัตโนมัติให้เข้ากับค่าต่ำสุดและสูงสุด ซึ่งอาจจะไม่ใช่ 0 ถึง 255 เช่นถ้าตัดมาเฉพาะบางส่วนแบบนี้
plt.imshow(rup[70:160,320:430],cmap='gray')
plt.colorbar(pad=0.01)
plt.show()



แบบนี้สีที่ได้ก็จะต่างไปจากที่ควรจะเป็นจริงๆ ตรงที่ค่าความสว่าง 100 กลับกลายเป็นสีดำไป หากต้องการให้ปรับสเกลให้ไล่ตั้งแต่ 0 ถึง 255 จริงๆก็กำหนดค่า vmin กับ vmax ลงไปเองด้วย แบบนี้
plt.imshow(rup[70:160,320:430],vmin=0,vmax=255,cmap='gray')
plt.colorbar(pad=0.01)
plt.show()






ความโปร่งใส

ภาพบางสกุลเช่น .png นอกจากจะเป็นภาพสีที่มีค่าสี ๓ สีแล้ว ยังมีค่าความโปร่งใส ซึ่งทำให้จำนวนสีไม่ใช่ ๓​ แต่เป็น ๔

หากเปิดด้วย cv2.imread() โดยไม่ได้ใส่แฟล็กอะไร แม้ว่าจะเป็นภาพที่มีค่าความโปร่งใสอยู่ก็จะไม่ได้ค่าความโปร่งใสติดมาด้วย ขนาดของมิติที่ ๓ จึงยังคงเป็น ๓

ตัวอย่างเช่น อ่านภาพนี้ซึ่งมีฉากหลังโปร่งใส

teto02c01.png
rup = cv2.imread('teto02c1.png')
print(rup.shape) # ได้ (450, 600, 3)
plt.imshow(rup[:,:,::-1])
plt.show()



เพื่อที่จะให้ภาพที่มีค่าความโปร่งใสอยู่ถูกอ่านออกมาได้อย่างถูกต้องด้วย ตอนอ่านไฟล์ให้ใส่แฟล็ก cv2.IMREAD_UNCHANGED

แต่พอมีค่าความโปร่งแสงขึ้นมาเป็นสีที่ ๔​ แล้ว เวลาใช้ imshow() จะกลับแถวโดยใช้ [:,:,::-1] แบบนี้ไม่ได้เพราะถ้า ::-1 แบบนี้ลำดับจะกลายเป็น 3,2,1,0 ให้ใส่ลำดับไปโดยตรง [:,:,[2,1,0,3]] ให้สลับเฉพาะแค่ ๓ ตัวแรก

ตัวอย่าง
rup = cv2.imread('teto02c1.png',cv2.IMREAD_UNCHANGED)
print(rup.shape) # ได้ (450, 600, 4)
plt.imshow(rup[:,:,[2,1,0,3]])
plt.show()






การสร้างภาพขึ้นมาใหม่

เนื่องจากข้อมูลภาพเมื่ออยู่ในโปรแกรมไพธอนก็คือตัวอาเรย์ของ numpy นั่นเอง หากเราจะสร้างอาเรย์ขึ้นมาเพื่อแทนภาพก็ทำได้

ตอนสร้างควรกำหนด dtype ของอาเรย์เป็น uint8 ไปด้วย เพื่อให้ทำงานได้ถูกต้องใน cv2 (แม้ว่าบางครั้งอาจจะไม่จำเป็นก็ตาม แต่มีหลายกรณีที่จำเป็น)

ตัวอย่างเช่น สร้างอาเรย์ที่มีแต่ค่า 0 แล้วค่อยๆเติมสีเข้าไปในแต่ละช่อง
arr = np.zeros([200,300,3],dtype=np.uint8)
arr[20:180,20:200,0] = 255 # วาดสีน้ำเงิน
arr[50:150,50:250,1] = 200 # วาดสีเขียว
arr[120:180,150:270,2] = 155 # วาดสีแดง
plt.imshow(arr[:,:,::-1])
plt.show()



เพียงแต่ต้องไม่ลืมว่าขณะแสดงผลด้วย imshow() มิติที่ ๓ จะเรียงเป็น [แดง, เขียว, น้ำเงิน] เมื่อนำมาใช้ใน cv2 จึงเปลี่ยนเป็น [น้ำเงิน, เขียว, แดง]




การบันทึกภาพลงไฟล์ด้วย cv2.imwrite

คำสั่งสำหรับนำข้อมูลภาพจากอาเรย์มาบันทึกลงในไฟล์คือ cv2.imwrite

ลำดับ ชื่อ สิ่งที่ต้องใส่ ชนิดข้อมูล
1 filename ชื่อไฟล์ str
2 img อาเรย์ของรูปภาพ np.array
3 params พารามิเตอร์เพิ่มเติม tuple ของ flag (int)

ชนิดของไฟล์ที่บันทึกจะขึ้นอยู่กับชื่อ โดยดูตรงสกุลไฟล์ เช่น .png, .jpg (หรือ .jpeg), .tif (หรือ .tiff), .bmp จะได้เป็นชนิดนั้นโดยอัตโนมัติ

ตัวอย่าง ลองสร้างอาเรย์ง่ายๆขึ้นมาอันหนึ่ง แล้วบันทึกเป็นภาพ (สำหรับวิธีการสร้างนั้นใช้คำสั่งของ numpy จะไม่อธิบายละเอียด อาจอ่านเพิ่มเติมได้ใน numpy & matplotlib บทที่ ๔)
rup = np.repeat(np.repeat((np.arange(0,20*25*3*100,100)%256).reshape(20,25,3),20,0),15,1)
cv2.imwrite('imw02c01.jpg',rup)

imw02c01.jpg

ในส่วนของพารามิเตอร์เพิ่มเติมนั้นเป็นแฟล็กที่ไว้ใช้กำหนดรายละเอียดรูปแบบของภาพที่จะได้ จะใส่หรือไม่ใส่ก็ได้

สำหรับการใส่จะมีวิธีใช้ที่ยุ่งเล็กน้อย คือให้ใส่ในรูปของทูเพิลของคู่ (แฟล็กของพารามิเตอร์, ค่า) แบบนี้

แฟล็กที่ใช้ได้ใน imwrite นั้นมีหลายตัว อาจลองดูแฟล็กทั้งหมดที่มีได้โดยพิมพ์
print('\n'.join(['%s: %d'%(x,getattr(cv2,x)) for x in dir(cv2) if 'IMWRITE' in x]))

ในที่นี้ขอยกตัวอย่างการใช้ส่วนหนึ่ง เช่นกรณีบันทึกภาพ jpg สามารถใส่แฟล็ก cv2.IMWRITE_JPEG_QUALITY ลงไปเพื่อกำหนดคุณภาพ ตั้งแต่ 0 ถึง 100 (หากไม่ใส่ ค่าตั้งต้นเป็น 95) ยิ่งคุณภาพต่ำขนาดยิ่งเล็ก แต่ภาพอาจจะออกมาดูไม่ดี

ลองเอาภาพเดิมมาบันทึกโดยปรับแฟล็กกำหนดคุณภาพของภาพ
cv2.imwrite('imw02c02.jpg',rup,(cv2.IMWRITE_JPEG_QUALITY,50))
cv2.imwrite('imw02c03.jpg',rup,(cv2.IMWRITE_JPEG_QUALITY,0))

ภาพคุณภาพ 50

imw02c02.jpg

ภาพคุณภาพ 0

imw02c03.jpg

จะเห็นได้ถึงความแตกต่าง ยิ่งคุณภาพต่ำภาพก็ยิ่งแตก

สำหรับภาพที่จะบันทึกเป็น .png นั้นสามารถใส่แฟล็ก cv2.IMWRITE_PNG_COMPRESSION เพื่อกำหนดระดับการบีบอัดไฟล์ ใส่เป็นเลขได้ตั้งแต่ 0 ถึง 9 โดยถ้าไม่ใส่ ค่าตั้งต้นคือ 3 ยิ่งใส่ก็จะยิ่งได้ไฟล์ที่กินเนื้อที่มาก แต่ก็จะใช้เวลาเขียนนานขึ้น
rup = np.repeat(np.repeat((np.arange(0,20*20*3*150,150)%256).reshape(20,20,3),20,0),20,1)
cv2.imwrite('imw02c04.png',rup,(cv2.IMWRITE_PNG_COMPRESSION,9))

imw02c04.jpg




การบันทึกภาพลงไฟล์ด้วยมอดูลอื่น

นอกจากจะใช้ฟังก์ชันของ cv2 โดยตรงแล้ว ใน matplotlib เองก็มีคำสั่งสำหรับเขียนไฟล์ คือ imsave จะใช้แทนก็ได้เช่นกัน เพียงแต่ถ้าใช้กับภาพสีที่อ่านโดย cv2 จะต้องไม่ลืมเรียงลำดับอาเรย์กลับเป็น [แดง, เขียว, น้ำเงิน]
import matplotlib.image as mpimg
mpimg.imsave('rupmpl.jpg',rup[:,:,::-1])

ถ้าเป็นภาพขาวดำก็ไม่มีปัญหาเรื่องลำดับสี แต่เวลาใช้ต้องกำหนด cmap ไม่เช่นนั้นจะออกมาเป็นสี viridis เหลืองเขียวม่วงแทน

อย่างไรก็ตาม ถึงตะกำหนด cmap='gray' ผลที่ได้ออกมาก็จะเป็นภาพชนิดสี (แค่ค่าของ ๓​ สีเท่ากัน) จึงไม่แนะนำให้ใช้ ยกเว้นต้องการเปลี่ยนภาพขาวดำให้เป็นภาพไล่สีตาม colormap

เช่นถ้าต้องการเอาภาพมาเปิดในโหมดขาวดำแล้วกำหนดเป็นสีโทนทองแดงแบบนี้ก็ทำได้ สวยไปอีกแบบ

rin02c01.jpg
rin = cv2.imread('rin02c01.jpg',cv2.IMREAD_GRAYSCALE)
mpimg.imsave('rin02c02.jpg',rin,cmap='copper')

rin02c02.jpg

นอกจากนี้หากใช้มอดูลอื่นๆเช่น imageio หรือ skimage ก็มีฟังก์ชัน imsave สำหรับบันทึกภาพเช่นกัน แต่ก็ต้องเปลี่ยนลำดับสี เช่นเดียวกับเมื่อใช้ matplotlib
from skimage import io
io.imsave('rupskimage.jpg',rup[:,:,::-1])

import imageio
imageio.imsave('rupimageio.jpg',rup[:,:,::-1])

ดังนั้นหากอ่านอาเรย์มาด้วย cv2.imread() ก็เขียนกลับด้วย cv2.imwrite() จะสะดวกที่สุด เพราะไม่ต้องกลับลำดับสี




ทิ้งท้ายบท

ที่ได้เขียนถึงในบทนี้เป็นแค่พื้นฐานการอ่านและเขียนไฟล์รูปภาพด้วย cv2 ยังไม่ได้เข้าเรื่องการแก้ไขหรือวิเคราะห์ภาพมากนัก

ความจริงแล้วเมื่อได้ข้อมูลรูปภาพออกมาเป็นอาเรย์แบบนี้แล้วถ้าจะใช้ฟังก์ชันของ numpy จัดการอะไรต่างๆก็สามารถแก้ไขหรือวิเคราะห์ภาพได้เช่นกัน โดยไม่ต้องใช้ฟังก์ชันใน cv2

แต่แบบนั้นก็จะไม่ได้ใช้ความสามารถของ opencv ซึ่งมีฟังก์ชันที่ช่วยในการจัดการแก้ไขปรับแต่งรูปภาพอยู่มากมายซึ่งใช้งานได้สะดวก

ในบทจากนี้ไปก็จะค่อยๆแนะนำฟังก์ชันสำหรับจัดการภาพเหล่านั้นไปเรื่อยๆทีละนิดไปตามลำดับ




อ่านบทถัดไป >> บทที่ ๓



-----------------------------------------

囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧

ดูสถิติของหน้านี้

หมวดหมู่

-- คอมพิวเตอร์ >> เขียนโปรแกรม >> opencv
-- คอมพิวเตอร์ >> เขียนโปรแกรม >> python >> numpy
-- คอมพิวเตอร์ >> เขียนโปรแกรม >> python >> matplotlib

ไม่อนุญาตให้นำเนื้อหาของบทความไปลงที่อื่นโดยไม่ได้ขออนุญาตโดยเด็ดขาด หากต้องการนำบางส่วนไปลงสามารถทำได้โดยต้องไม่ใช่การก๊อปแปะแต่ให้เปลี่ยนคำพูดเป็นของตัวเอง หรือไม่ก็เขียนในลักษณะการยกข้อความอ้างอิง และไม่ว่ากรณีไหนก็ตาม ต้องให้เครดิตพร้อมใส่ลิงก์ของทุกบทความที่มีการใช้เนื้อหาเสมอ

目录

从日本来的名言
模块
-- numpy
-- matplotlib

-- pandas
-- manim
-- opencv
-- pyqt
-- pytorch
机器学习
-- 神经网络
javascript
蒙古语
语言学
maya
概率论
与日本相关的日记
与中国相关的日记
-- 与北京相关的日记
-- 与香港相关的日记
-- 与澳门相关的日记
与台湾相关的日记
与北欧相关的日记
与其他国家相关的日记
qiita
其他日志

按类别分日志



ติดตามอัปเดตของบล็อกได้ที่แฟนเพจ

  查看日志

  推荐日志

ตัวอักษรกรีกและเปรียบเทียบการใช้งานในภาษากรีกโบราณและกรีกสมัยใหม่
ที่มาของอักษรไทยและความเกี่ยวพันกับอักษรอื่นๆในตระกูลอักษรพราหมี
การสร้างแบบจำลองสามมิติเป็นไฟล์ .obj วิธีการอย่างง่ายที่ไม่ว่าใครก็ลองทำได้ทันที
รวมรายชื่อนักร้องเพลงกวางตุ้ง
ภาษาจีนแบ่งเป็นสำเนียงอะไรบ้าง มีความแตกต่างกันมากแค่ไหน
ทำความเข้าใจระบอบประชาธิปไตยจากประวัติศาสตร์ความเป็นมา
เรียนรู้วิธีการใช้ regular expression (regex)
การใช้ unix shell เบื้องต้น ใน linux และ mac
g ในภาษาญี่ปุ่นออกเสียง "ก" หรือ "ง" กันแน่
ทำความรู้จักกับปัญญาประดิษฐ์และการเรียนรู้ของเครื่อง
ค้นพบระบบดาวเคราะห์ ๘ ดวง เบื้องหลังความสำเร็จคือปัญญาประดิษฐ์ (AI)
หอดูดาวโบราณปักกิ่ง ตอนที่ ๑: แท่นสังเกตการณ์และสวนดอกไม้
พิพิธภัณฑ์สถาปัตยกรรมโบราณปักกิ่ง
เที่ยวเมืองตานตง ล่องเรือในน่านน้ำเกาหลีเหนือ
ตระเวนเที่ยวตามรอยฉากของอนิเมะในญี่ปุ่น
เที่ยวชมหอดูดาวที่ฐานสังเกตการณ์ซิงหลง
ทำไมจึงไม่ควรเขียนวรรณยุกต์เวลาทับศัพท์ภาษาต่างประเทศ