การประมวลผลภาพ OpenCV

Kar Pramwl Phl Phaph Opencv



เราจะศึกษาวิธีการประมวลผลภาพในบทความนี้ เราจะตรวจสอบหัวข้อพื้นฐานแต่มีความสำคัญในการมองเห็นคอมพิวเตอร์และการเรียนรู้ของเครื่อง เทคนิคการประมวลผลภาพพื้นฐานเหล่านี้สามารถแก้ปัญหาที่ซับซ้อนได้ เช่น ชุดข้อมูล ด้วยเหตุนี้ จึงมีหกขั้นตอนพื้นฐานในการประมวลผลภาพ ซึ่งแสดงรายการไว้ด้านล่าง:
  1. การแปลรูปภาพ
  2. การหมุนภาพ
  3. ภาพเลขคณิต
  4. การพลิกภาพ
  5. การครอบตัดรูปภาพ
  6. การปรับขนาดรูปภาพ

ตอนนี้ เราจะอธิบายรายละเอียดหัวข้อการประมวลผลภาพที่กล่าวถึงข้างต้นทั้งหมด

1. การแปลรูปภาพ

การแปลภาพเป็นวิธีการประมวลผลภาพที่ช่วยให้เราย้ายภาพไปตามแกน x และ y เราสามารถเลื่อนภาพขึ้น ลง ขวา ซ้าย หรือผสมผสานใดๆ







เราสามารถกำหนดเมทริกซ์การแปลด้วยสัญลักษณ์ M และเราสามารถแสดงในรูปแบบทางคณิตศาสตร์ได้ดังที่แสดงด้านล่าง:





เราสามารถเข้าใจแนวคิดของภาพการแปลผ่านโปรแกรมนี้





รหัสหลาม: เราจะคงชื่อโปรแกรมต่อไปนี้เป็น translate.py .

# นำเข้าแพ็คเกจที่จำเป็น

นำเข้า อ้วน เช่น เช่น.

นำเข้า หาเรื่อง

นำเข้า อิมิวทิล

นำเข้า cv2

# เราใช้ตัวแยกวิเคราะห์อาร์กิวเมนต์

ap_obj = หาเรื่อง อาร์กิวเมนต์ Parser ( )

ap_obj add_argument ( '-k' , '--ภาพ' , ที่จำเป็น = จริง ,

ช่วย = 'ตำแหน่งของไฟล์รูปภาพ' )

หาเรื่อง = ของใคร ( ap_obj parse_args ( ) )

# โหลดภาพและแสดงบนหน้าจอ

ภาพ = cv2 ฉันอ่าน ( หาเรื่อง [ 'ภาพ' ] )

cv2 แสดง ( 'Original_image' , ภาพ )

# การแปลรูปภาพเป็นเมทริกซ์ NumPy ซึ่งระบุไว้ด้านล่าง:

# [[1, 0, shiftX], [0, 1, shiftY]]

# เราจะใช้เมทริกซ์ NumPy ด้านบนเพื่อเลื่อนรูปภาพไปตาม

# ทิศทางแกน x และแกน y สำหรับสิ่งนี้ เราต้องส่งค่าพิกเซล

# ในโปรแกรมนี้ เราจะย้ายรูปภาพไปทางขวา 30 พิกเซล

# และ 70 พิกเซลไปทางด้านล่าง

การแปล_mat = เช่น. ลอย32 ( [ [ 1 , 0 , 30 ] , [ 0 , 1 , 70 ] ] )

รูปภาพ_การแปล = cv2 warpAffine ( ภาพ , การแปล_mat ,

( ภาพ. รูปร่าง [ 1 ] , ภาพ. รูปร่าง [ 0 ] ) )

cv2 แสดง ( 'การแปลรูปภาพลงและขวา' , รูปภาพ_การแปล )

# ตอนนี้เราจะใช้เมทริกซ์ NumPy ด้านบนเพื่อเลื่อนรูปภาพไปตาม

# ทิศทางแกน x (ซ้าย) และแกน y (ขึ้น)

# ที่นี่เราจะย้ายภาพไปทางซ้าย 50 พิกเซล

# และ 90 พิกเซลไปทางด้านบน

การแปล_mat = เช่น. ลอย32 ( [ [ 1 , 0 , - ห้าสิบ ] , [ 0 , 1 , - 90 ] ] )

รูปภาพ_การแปล = cv2 warpAffine ( ภาพ , การแปล_mat ,

( ภาพ. รูปร่าง [ 1 ] , ภาพ. รูปร่าง [ 0 ] ) )

cv2 แสดง ( 'การแปลรูปภาพขึ้นและซ้าย' , รูปภาพ_การแปล )

cv2 รอคีย์ ( 0 )

บรรทัดที่ 1 ถึง 5: เรากำลังนำเข้าแพ็คเกจที่จำเป็นทั้งหมดสำหรับโปรแกรมนี้ เช่น OpenCV, argparser และ NumPy โปรดทราบว่ามีห้องสมุดอีกแห่งที่เลียนแบบได้ นี่ไม่ใช่แพ็คเกจของ OpenCV นี่เป็นเพียงห้องสมุดที่จะแสดงการประมวลผลภาพเดียวกันได้อย่างง่ายดาย



imutils ของไลบรารีจะไม่ถูกรวมโดยอัตโนมัติเมื่อเราติดตั้ง OpenCV ดังนั้นในการติดตั้ง imutils เราต้องใช้วิธีต่อไปนี้:

pip ติดตั้ง imutils

บรรทัดที่ 8 ถึง 15: เราสร้าง agrparser และโหลดรูปภาพของเรา

บรรทัดที่ 24 ถึง 25: ส่วนโปรแกรมนี้เป็นที่ที่การแปลเกิดขึ้น เมทริกซ์การแปลบอกเราว่าภาพจะเลื่อนขึ้นหรือลงหรือไปทางซ้ายหรือขวากี่พิกเซล เนื่องจาก OpenCV กำหนดให้ค่าเมทริกซ์อยู่ในอาร์เรย์ทศนิยม เมทริกซ์การแปลจึงรับค่าในอาร์เรย์ทศนิยม

แถวแรกของเมทริกซ์การแปลมีลักษณะดังนี้:

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

ตอนนี้เราจะกำหนดแถวที่สองของเมทริกซ์ดังนี้:

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

ในโปรแกรมก่อนหน้านี้ที่บรรทัดที่ 24 เรากำหนด t x = 30 และ t วาย = 70 เราจึงย้ายรูปภาพไปทางด้านขวา 30 พิกเซลและเลื่อนลงด้านล่าง 70 พิกเซล

แต่กระบวนการแปลรูปภาพหลักเกิดขึ้นที่บรรทัดที่ 25 ซึ่งเรากำหนดเมทริกซ์การแปล cv2.warpAffine . ในฟังก์ชันนี้ เรากำลังส่งพารามิเตอร์สามตัว: พารามิเตอร์แรกคือรูปภาพ พารามิเตอร์ที่สองคือเมทริกซ์การแปล และพารามิเตอร์ที่สามคือมิติของรูปภาพ

บรรทัดที่ 27: บรรทัดที่ 27 จะแสดงผลในเอาต์พุต

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

บรรทัดที่ 33 ถึง 34: ในโปรแกรมก่อนหน้านี้ที่บรรทัดที่ 33 เรากำหนด t x = -50 และ t วาย = -90. ดังนั้นเราจึงย้ายภาพ 50 พิกเซลไปทางด้านซ้ายและ 90 พิกเซลขึ้น แต่กระบวนการแปลภาพหลักเกิดขึ้นที่บรรทัดที่ 34 ซึ่งเรากำหนดเมทริกซ์การแปล cv2.warpAffine .

สาย 36 : บรรทัดที่ 36 จะแสดงผลตามที่แสดงในเอาต์พุต

ในการเรียกใช้โค้ดก่อนหน้า เราต้องกำหนดเส้นทางของรูปภาพตามที่ระบุด้านล่าง

เอาท์พุต: หลาม translate.py –image กระรอก.jpg

ตอนนี้เราจะใช้โปรแกรมแปลรูปภาพเดียวกันโดยใช้ อิมิวทิล ห้องสมุด. ห้องสมุดนี้ใช้งานง่ายมากสำหรับการประมวลผลภาพ ในห้องสมุดนี้ เราไม่ต้องคิดเกี่ยวกับ cv2.warpAffine เพราะห้องสมุดนี้จะดูแลเรื่องนี้ ลองใช้โปรแกรมแปลภาพนี้โดยใช้ไลบรารี imutils

รหัสหลาม: เราจะคงชื่อโปรแกรมต่อไปนี้เป็น translate_imutils.py .

#นำเข้าแพ็คเกจที่จำเป็น

นำเข้า อ้วน เช่น เช่น.

นำเข้า หาเรื่อง

นำเข้า อิมิวทิล

นำเข้า cv2

# ฟังก์ชั่นนี้ใช้การแปลรูปภาพและ

# ส่งคืนรูปภาพที่แปลไปยังฟังก์ชันการโทร

แน่นอน แปลภาษา ( ภาพ , x , วาย ) :

การแปล_matrix = เช่น. ลอย32 ( [ [ 1 , 0 , x ] , [ 0 , 1 , วาย ] ] )

รูปภาพ_การแปล = cv2 warpAffine ( ภาพ , การแปล_matrix ,

( ภาพ. รูปร่าง [ 1 ] , ภาพ. รูปร่าง [ 0 ] ) )

กลับ รูปภาพ_การแปล

# สร้างตัวแยกวิเคราะห์อาร์กิวเมนต์และแยกวิเคราะห์อาร์กิวเมนต์

ap = หาเรื่อง อาร์กิวเมนต์ Parser ( )

ap add_argument ( '-ผม' , '--ภาพ' , ที่จำเป็น = จริง , ช่วย = 'เส้นทางสู่ภาพ' )

หาเรื่อง = ของใคร ( ap parse_args ( ) )

# โหลดภาพและแสดงบนหน้าจอ

ภาพ = cv2 ฉันอ่าน ( หาเรื่อง [ 'ภาพ' ] )

cv2 แสดง ( 'Original_image' , ภาพ )

รูปภาพ_การแปล = อิมิวทิล. แปลภาษา ( ภาพ , 10 , 70 )

cv2 แสดง ( 'การแปลรูปภาพไปทางขวาและด้านล่าง' ,

รูปภาพ_การแปล )

cv2 รอคีย์ ( 0 )

บรรทัดที่ 9 ถึง 13: ส่วนนี้ของโปรแกรมเป็นที่ที่การแปลเกิดขึ้น เมทริกซ์การแปลจะแจ้งให้เราทราบว่าภาพจะเลื่อนขึ้นหรือลงหรือไปทางซ้ายหรือขวากี่พิกเซล

บรรทัดเหล่านี้ได้รับการอธิบายแล้ว แต่ตอนนี้เรากำลังจะสร้างฟังก์ชันที่เรียกว่า translate () และส่งพารามิเตอร์ที่แตกต่างกันสามตัวเข้าไป รูปภาพทำหน้าที่เป็นพารามิเตอร์แรก ค่า x และ y ของเมทริกซ์การแปลสอดคล้องกับพารามิเตอร์ที่สองและสาม

บันทึก : ไม่จำเป็นต้องกำหนดฟังก์ชั่นการแปลนี้ภายในโปรแกรมเพราะมันรวมอยู่ในแพ็คเกจห้องสมุด imutils แล้ว ฉันใช้มันในโปรแกรมเพื่ออธิบายอย่างตรงไปตรงมา เราสามารถเรียกใช้ฟังก์ชันนี้ได้โดยตรงด้วย imutils ดังแสดงในบรรทัดที่ 24

บรรทัดที่ 24: โปรแกรมก่อนหน้านี้จะแสดงให้เห็นว่าที่บรรทัดที่ 24 เรากำหนด tx = 10 และ ty = 70 ดังนั้นเราจึงย้ายรูปภาพไปทางด้านขวา 10 พิกเซลและลงด้านล่าง 70 พิกเซล

ในโปรแกรมนี้ เราไม่สนใจเกี่ยวกับฟังก์ชัน cv2.warpAffine ใดๆ เนื่องจากฟังก์ชันเหล่านี้อยู่ในแพ็คเกจไลบรารี imutils แล้ว

ในการเรียกใช้โค้ดก่อนหน้า เราต้องกำหนดเส้นทางของรูปภาพตามที่ระบุด้านล่าง:

เอาท์พุต:

หลาม imutils พาย --ภาพกระรอก jpg

2. การหมุนภาพ

เราได้ศึกษาวิธีการแปล (เช่น การเลื่อน) ภาพขึ้น ลง ซ้าย และขวาในบทเรียนที่แล้ว (หรือการผสมผสานใดๆ) ต่อไป เราจะพูดถึงการหมุนที่เกี่ยวข้องกับการประมวลผลภาพ

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

คล้ายกับการแปลและอาจไม่น่าแปลกใจ การหมุนตามมุม, theta ถูกกำหนดโดยการสร้างเมทริกซ์ M ในรูปแบบต่อไปนี้:

เมทริกซ์นี้อาจหมุนเวกเตอร์ทีตาองศา (ทวนเข็มนาฬิกา) รอบจุดกำเนิดที่กำหนด (x, y)-ระนาบคาร์ทีเซียน โดยปกติแล้ว ในสถานการณ์นี้ จุดกำเนิดจะเป็นจุดศูนย์กลางของภาพ แต่ในความเป็นจริง เราอาจกำหนดให้จุดสุ่ม (x, y) เป็นจุดศูนย์กลางการหมุนของเรา

จากนั้นภาพ R ที่หมุนจะถูกสร้างขึ้นจากภาพต้นฉบับ I โดยใช้การคูณเมทริกซ์แบบตรงไปตรงมา: R = IM

ในทางกลับกัน OpenCV ยังเสนอความสามารถเพิ่มเติมในการ (1) ปรับขนาด (เช่น ปรับขนาด) รูปภาพ และ (2) เสนอศูนย์กลางการหมุนตามอำเภอใจเพื่อทำการหมุนไปรอบๆ

เมทริกซ์การหมุนที่แก้ไขของเรา M แสดงอยู่ด้านล่าง:

เริ่มต้นด้วยการเปิดและสร้างไฟล์ใหม่ที่ชื่อว่า หมุน. py :

# การนำเข้าแพ็คเกจที่จำเป็น

นำเข้า อ้วน เช่น เช่น.

นำเข้า หาเรื่อง

นำเข้า อิมิวทิล

นำเข้า cv2

# สร้างวัตถุ argumentparser และแยกวิเคราะห์อาร์กิวเมนต์

อภ = หาเรื่อง อาร์กิวเมนต์ Parser ( )

อภ. add_argument ( '-k' , '--ภาพ' , ที่จำเป็น = จริง , ช่วย = 'เส้นทางภาพ' )

ข้อโต้แย้ง = ของใคร ( อภ. parse_args ( ) )

ภาพ = cv2 ฉันอ่าน ( ข้อโต้แย้ง [ 'ภาพ' ] )

cv2 แสดง ( 'Original_image' , ภาพ )

# คำนวณศูนย์กลางของภาพโดยใช้ขนาดของภาพ

( ความสูง , ความกว้าง ) = ภาพ. รูปร่าง [ : 2 ]

( เซ็นเตอร์เอ็กซ์ , ศูนย์ย ) = ( ความกว้าง / 2 , ความสูง / 2 )

# ตอนนี้ใช้ cv2 เราจะหมุนภาพ 55 องศาถึง

# กำหนดเมทริกซ์การหมุนโดยใช้ getRotationMatrix2D()

เมทริกซ์การหมุน = cv2 getRotationMatrix2D ( ( เซ็นเตอร์เอ็กซ์ , ศูนย์ย ) , 55 , 1.0 )

ภาพหมุน = cv2 warpAffine ( ภาพ , เมทริกซ์การหมุน , ( ความกว้าง , ความสูง ) )

cv2 แสดง ( 'หมุนภาพ 55 องศา' , ภาพหมุน )

cv2 รอคีย์ ( 0 )

# ภาพจะหมุน -85 องศา

เมทริกซ์การหมุน = cv2 getRotationMatrix2D ( ( เซ็นเตอร์เอ็กซ์ , ศูนย์ย ) , - 85 , 1.0 )

ภาพหมุน = cv2 warpAffine ( ภาพ , เมทริกซ์การหมุน , ( ความกว้าง , ความสูง ) )

cv2 แสดง ( 'หมุนภาพ -85 องศา' , ภาพหมุน )

cv2 รอคีย์ ( 0 )

บรรทัดที่ 1 ถึง 5: เรากำลังนำเข้าแพ็คเกจที่จำเป็นทั้งหมดสำหรับโปรแกรมนี้ เช่น OpenCV, argparser และ NumPy โปรดทราบว่ามีห้องสมุดอีกแห่งที่เลียนแบบได้ นี่ไม่ใช่แพ็คเกจของ OpenCV นี่เป็นเพียงไลบรารีที่จะใช้แสดงการประมวลผลภาพเดียวกันได้อย่างง่ายดาย

imutils ของไลบรารีจะไม่ถูกรวมโดยอัตโนมัติเมื่อเราติดตั้ง OpenCV OpenCV ติดตั้ง imutils เราต้องใช้วิธีการต่อไปนี้:

pip ติดตั้ง imutils

บรรทัดที่ 8 ถึง 14: เราสร้าง agrparser และโหลดรูปภาพของเรา ใน argparser นี้ เราใช้อาร์กิวเมนต์รูปภาพเพียงตัวเดียว ซึ่งจะบอกเส้นทางของรูปภาพที่เราจะใช้ในโปรแกรมนี้เพื่อแสดงการหมุน

เมื่อหมุนรูปภาพ เราต้องกำหนดจุดหมุนของการหมุน ส่วนใหญ่แล้วคุณจะต้องการหมุนรูปภาพรอบศูนย์กลาง แต่ OpenCV ให้คุณเลือกจุดสุ่มแทน เพียงแค่หมุนภาพไปรอบๆ จุดศูนย์กลาง

บรรทัดที่ 17 ถึง 18 นำความกว้างและความสูงของภาพตามลำดับ แล้วหารแต่ละมิติด้วยสองส่วนเพื่อสร้างศูนย์กลางของภาพ

เราสร้างเมทริกซ์เพื่อหมุนรูปภาพในลักษณะเดียวกับที่เรากำหนดเมทริกซ์เพื่อแปลรูปภาพ เราจะโทรหา cv2.getRotationMatrix2D ฟังก์ชันบนบรรทัดที่ 22 แทนที่จะสร้างเมทริกซ์ด้วยตนเองโดยใช้ NumPy (ซึ่งอาจยุ่งยากเล็กน้อย)

เดอะ cv2.getRotationMatrix2D ฟังก์ชันต้องการพารามิเตอร์สามตัว อินพุตแรกคือมุมการหมุนที่ต้องการ (ในกรณีนี้คือจุดกึ่งกลางของภาพ) จากนั้น Theta ใช้เพื่อระบุว่าเราจะหมุนภาพกี่องศา (ทวนเข็มนาฬิกา) ที่นี่เราจะหมุนภาพ 45 องศา ตัวเลือกสุดท้ายเกี่ยวข้องกับขนาดของรูปภาพ

แม้ว่าเราจะยังไม่ได้พูดถึงการปรับขนาดรูปภาพ คุณสามารถระบุเลขทศนิยมที่นี่ด้วย 1.0 ซึ่งแสดงว่าควรใช้รูปภาพในสัดส่วนเดิม อย่างไรก็ตาม หากคุณพิมพ์ค่าเป็น 2.0 รูปภาพจะมีขนาดเพิ่มขึ้นเป็นสองเท่า ตัวเลข 0.5 จะลดขนาดของภาพเช่นนั้น

บรรทัดที่ 22 ถึง 23: หลังจากได้รับเมทริกซ์การหมุนของเรา M จาก cv2.getRotationMatrix2D ฟังก์ชั่น เราหมุนภาพของเราโดยใช้ปุ่ม cv2.warpAffine เทคนิคในบรรทัดที่ 23 ฟังก์ชันป้อนรูปภาพที่เราต้องการหมุนเป็นอันดับแรก ความกว้างและความสูงของภาพที่ส่งออกจะถูกกำหนดพร้อมกับเมทริกซ์การหมุนของเรา M. ในบรรทัดที่ 23 รูปภาพจะถูกหมุน 55 องศา

คุณจะสังเกตเห็นว่าภาพของเราถูกหมุน

บรรทัดที่ 28 ถึง 30 เป็นการหมุนรอบที่สอง บรรทัดที่ 22–23 ของโค้ดจะเหมือนกัน ยกเว้นว่าคราวนี้เราจะหมุนไป -85 องศา ซึ่งตรงข้ามกับ 55

เราเพิ่งหมุนภาพไปรอบๆ จุดศูนย์กลางจนถึงจุดนี้ ถ้าเราต้องการหมุนภาพไปรอบๆ จุดสุ่มล่ะ?

เริ่มต้นด้วยการเปิดและสร้างไฟล์ใหม่ที่ชื่อว่า หมุน. py:

# การนำเข้าแพ็คเกจที่จำเป็น

นำเข้า อ้วน เช่น เช่น.

นำเข้า หาเรื่อง

นำเข้า อิมิวทิล

นำเข้า cv2

# สร้างวัตถุ argumentparser และแยกวิเคราะห์อาร์กิวเมนต์

ap_obj = หาเรื่อง อาร์กิวเมนต์ Parser ( )

ap_obj add_argument ( '-k' , '--ภาพ' , ที่จำเป็น = จริง , ช่วย = 'เส้นทางภาพ' )

การโต้แย้ง = ของใคร ( ap_obj parse_args ( ) )

# โหลดภาพและแสดงบนหน้าจอ

ภาพ = cv2 ฉันอ่าน ( การโต้แย้ง [ 'ภาพ' ] )

cv2 แสดง ( 'Original_image' , ภาพ )

# คำนวณศูนย์กลางของภาพโดยใช้ขนาดของภาพ

( ความสูง , ความกว้าง ) = ภาพ. รูปร่าง [ : 2 ]

( เซ็นเตอร์เอ็กซ์ , ศูนย์ย ) = ( ความกว้าง / 2 , ความสูง / 2 )

# ตอนนี้ใช้ cv2 เราจะหมุนภาพ 55 องศาถึง

# กำหนดเมทริกซ์การหมุนโดยใช้ getRotationMatrix2D()

เมทริกซ์การหมุน = cv2 getRotationMatrix2D ( ( เซ็นเตอร์เอ็กซ์ , ศูนย์ย ) , 55 , 1.0 )

ภาพหมุน = cv2 warpAffine ( ภาพ , เมทริกซ์การหมุน , ( ความกว้าง , ความสูง ) )

cv2 แสดง ( 'หมุนภาพ 55 องศา' , ภาพหมุน )

cv2 รอคีย์ ( 0 )

# ภาพจะหมุน -85 องศา

เมทริกซ์การหมุน = cv2 getRotationMatrix2D ( ( เซ็นเตอร์เอ็กซ์ , ศูนย์ย ) , - 85 , 1.0 )

ภาพหมุน = cv2 warpAffine ( ภาพ , เมทริกซ์การหมุน , ( ความกว้าง , ความสูง ) )

cv2 แสดง ( 'หมุนภาพ -85 องศา' , ภาพหมุน )

cv2 รอคีย์ ( 0 )

# การหมุนภาพจากจุดใดจุดหนึ่งโดยพลการไม่ใช่จากจุดศูนย์กลาง

เมทริกซ์การหมุน = cv2 getRotationMatrix2D ( ( เซ็นเตอร์เอ็กซ์ - 40 , ศูนย์ Y - 40 ) , 55 , 1.0 )

ภาพหมุน = cv2 warpAffine ( ภาพ , เมทริกซ์การหมุน , ( ความกว้าง , ความสูง ) )

cv2 แสดง ( 'การหมุนภาพจากจุดโดยพลการ' , ภาพหมุน )

cv2 รอคีย์ ( 0 )

บรรทัดที่ 34 ถึง 35: ตอนนี้โค้ดนี้น่าจะดูเหมือนเป็นเรื่องธรรมดาสำหรับการหมุนวัตถุ หากต้องการหมุนรูปภาพไปรอบๆ จุด 40 พิกเซลไปทางซ้ายและ 40 พิกเซลเหนือจุดกึ่งกลาง เราจะสั่งให้ cv2.getRotationMatrix2D ฟังก์ชันให้ความสนใจกับพารามิเตอร์ตัวแรก

ภาพที่สร้างขึ้นเมื่อเราใช้การหมุนนี้แสดงอยู่ด้านล่าง:

เราสามารถเห็นได้ชัดเจนว่าจุดศูนย์กลางของการหมุนคือพิกัด (x, y) ซึ่งอยู่ทางซ้าย 40 พิกเซลและ 40 พิกเซลเหนือจุดศูนย์กลางที่คำนวณของรูปภาพ

3. ภาพเลขคณิต

อันที่จริง เลขคณิตของภาพเป็นเพียงการบวกเมทริกซ์โดยมีข้อจำกัดเพิ่มเติมเล็กน้อยเกี่ยวกับประเภทข้อมูลซึ่งเราจะกล่าวถึงในภายหลัง

เรามาใช้เวลาสักครู่เพื่ออธิบายพื้นฐานที่น่าสนใจของพีชคณิตเชิงเส้น

พิจารณารวมสองเมทริกซ์ถัดไป:

การบวกเมทริกซ์จะให้ผลลัพธ์อย่างไร คำตอบง่ายๆ คือผลรวมของรายการเมทริกซ์ ทีละองค์ประกอบ:

ง่ายพอใช่มั้ย

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

ตัวอย่างเช่น พิกเซลในภาพ RGB อยู่ระหว่าง [0, 255] จะเกิดอะไรขึ้นหากเราพยายามเพิ่ม 10 พิกเซลด้วยความเข้ม 250 ในขณะที่มองดู

เราจะได้ค่า 260 ถ้าเราใช้หลักการเลขคณิตมาตรฐาน 260 ไม่ใช่ค่าที่ถูกต้อง เนื่องจากภาพ RGB แสดงเป็นจำนวนเต็ม 8 บิตที่ไม่ได้ลงชื่อ

แล้วจะเกิดอะไรขึ้น? เราควรตรวจสอบเพื่อให้แน่ใจว่าไม่มีพิกเซลใดเกินช่วง [0, 255] ตัดทุกพิกเซลให้มีค่าระหว่าง 0 ถึง 255 หรือไม่

หรือเราจะ 'ล้อมรอบ' และดำเนินการโมดูลัส? ตามกฎโมดูลัส การเพิ่ม 10 ถึง 255 จะได้ค่าเป็น 9

การเพิ่มและการลบรูปภาพที่อยู่นอกช่วง [0, 255] ควรจัดการอย่างไร

ความจริงก็คือไม่มีเทคนิคใดถูกหรือผิด ทุกอย่างขึ้นอยู่กับวิธีการทำงานกับพิกเซลของคุณ และสิ่งที่คุณหวังว่าจะบรรลุ

แต่โปรดจำไว้ว่ามีความแตกต่างระหว่างการเพิ่มใน OpenCV และการเพิ่มใน NumPy การคำนวณโมดูลัสและ 'wrap around' จะทำโดย NumPy ในทางตรงกันข้าม OpenCV จะดำเนินการตัดและตรวจสอบให้แน่ใจว่าค่าพิกเซลไม่ออกจากช่วง [0, 255]

เริ่มต้นด้วยการสร้างไฟล์ใหม่ชื่อ arithmetic.py และเปิด:

# python arithmetic.py --image กระรอก.jpg

# การนำเข้าแพ็คเกจที่จำเป็น

นำเข้า อ้วน เช่น เช่น.

นำเข้า หาเรื่อง

นำเข้า อิมิวทิล

นำเข้า cv2

# สร้างวัตถุ argumentparser และแยกวิเคราะห์อาร์กิวเมนต์

apObj = หาเรื่อง อาร์กิวเมนต์ Parser ( )

apObj add_argument ( '-k' , '--ภาพ' , ที่จำเป็น = จริง , ช่วย = 'เส้นทางภาพ' )

ข้อโต้แย้ง = ของใคร ( apObj parse_args ( ) )

ภาพ = cv2 ฉันอ่าน ( ข้อโต้แย้ง [ 'ภาพ' ] )

cv2 แสดง ( 'Original_image' , ภาพ )

'''

ค่าพิกเซลของเราจะอยู่ในช่วง [0, 255]

เนื่องจากรูปภาพเป็นอาร์เรย์ NumPy ซึ่งจัดเก็บเป็นจำนวนเต็ม 8 บิตที่ไม่ได้ลงชื่อ

เมื่อใช้ฟังก์ชันเช่น cv2.add และ cv2.subtract ค่าต่างๆ จะถูกตัดออก

ถึงช่วงนี้แม้ว่าจะเพิ่มหรือลบออกจากภายนอกก็ตาม

[0, 255] ช่วง นี่คือภาพประกอบ:

'''


พิมพ์ ( 'สูงสุด 255: {}' . รูปแบบ ( สตริง ( cv2 เพิ่ม ( เช่น. uint8 ( [ 201 ] ) ,

เช่น. uint8 ( [ 100 ] ) ) ) ) )

พิมพ์ ( 'ขั้นต่ำ 0: {}' . รูปแบบ ( สตริง ( cv2 ลบ ( เช่น. uint8 ( [ 60 ] ) ,

เช่น. uint8 ( [ 100 ] ) ) ) ) )

'''

เมื่อดำเนินการทางคณิตศาสตร์กับอาร์เรย์เหล่านี้โดยใช้ NumPy

ค่าจะล้อมรอบแทนที่จะถูกตัดไปที่

[0, 255]ช่วง เมื่อใช้รูปภาพ สิ่งสำคัญคือต้องคงสิ่งนี้ไว้

ในใจ.

'''


พิมพ์ ( 'ห่อรอบ ๆ: {}' . รูปแบบ ( สตริง ( เช่น. uint8 ( [ 201 ] ) + เช่น uint8 ( [ 100 ] ) ) ) )

พิมพ์ ( 'ห่อรอบ ๆ: {}' . รูปแบบ ( สตริง ( เช่น. uint8 ( [ 60 ] ) - เช่น. uint8 ( [ 100 ] ) ) ) )

'''

ลองคูณความสว่างของทุกพิกเซลในภาพของเราด้วย 101

ในการทำเช่นนี้ เราสร้างอาร์เรย์ NumPy ที่มีขนาดเท่ากับเมทริกซ์ของเรา

เติมด้วย 101 แล้วคูณด้วย 101 เพื่อสร้างอาร์เรย์ที่เติม

ด้วย 101 วินาที ในที่สุดเราก็รวมภาพทั้งสองเข้าด้วยกัน

คุณจะสังเกตได้ว่าตอนนี้ภาพจะ 'สว่างขึ้น'

'''


เมทริกซ์ = เช่น. คน ( ภาพ. รูปร่าง , dประเภท = 'uint8' ) * 101

เพิ่มรูปภาพแล้ว = cv2 เพิ่ม ( ภาพ , เมทริกซ์ )

cv2 แสดง ( 'ผลลัพธ์รูปภาพที่เพิ่ม' , เพิ่มรูปภาพแล้ว )

#ในทำนองเดียวกันเราอาจทำให้ภาพของเรามืดลงได้โดยการถ่าย

# 60 ห่างจากพิกเซลทั้งหมด

เมทริกซ์ = เช่น. คน ( ภาพ. รูปร่าง , dประเภท = 'uint8' ) * 60

ภาพ_subtracted = cv2 ลบ ( ภาพ , เมทริกซ์ )

cv2 แสดง ( 'ผลลัพธ์ภาพที่ถูกลบ' , ภาพ_subtracted )

cv2 รอคีย์ ( 0 )

บรรทัดที่ 1 ถึง 16 จะถูกใช้เพื่อดำเนินการตามกระบวนการปกติของเรา ซึ่งเกี่ยวข้องกับการนำเข้าแพ็คเกจ การกำหนดค่าตัวแยกวิเคราะห์อาร์กิวเมนต์ และการโหลดอิมเมจของเรา

จำได้ไหมว่าก่อนหน้านี้ฉันพูดถึงความแตกต่างระหว่างการเพิ่ม OpenCV และ NumPy อย่างไร ตอนนี้เราได้อธิบายอย่างละเอียดแล้ว มาดูกรณีเฉพาะเพื่อให้แน่ใจว่าเราเข้าใจ

มีการกำหนดอาร์เรย์ NumPy จำนวนเต็ม 8 บิต 8 บิตสองตัว สาย 26 . ค่า 201 เป็นองค์ประกอบเดียวในอาร์เรย์แรก แม้ว่าจะมีสมาชิกเพียงตัวเดียวในอาร์เรย์ที่สอง แต่ก็มีค่า 100 จากนั้นค่าจะถูกเพิ่มโดยใช้ฟังก์ชัน cv2.add ของ OpenCV

คุณคาดหวังว่าผลลัพธ์จะเป็นอย่างไร?

ตามหลักการเลขคณิตทั่วไป คำตอบควรเป็น 301 แต่จำไว้ว่าเรากำลังจัดการกับจำนวนเต็ม 8 บิตที่ไม่มีเครื่องหมาย ซึ่งสามารถอยู่ในช่วง [0, 255] เท่านั้น เนื่องจากเราใช้เมธอด cv2.add ดังนั้น OpenCV จึงจัดการการตัดและตรวจสอบให้แน่ใจว่าการเพิ่มจะส่งกลับผลลัพธ์สูงสุดที่ 255 เท่านั้น

บรรทัดแรกของรายการด้านล่างแสดงผลของการรันโค้ดนี้:

เลขคณิต พาย

สูงสุด 255 : [ [ 255 ] ]

ผลรวมทำให้เกิดจำนวน 255

ตามนั้น สาย 26 ใช้ cv2.subtract เพื่อทำการลบ อีกครั้ง เรากำหนดอาร์เรย์ NumPy จำนวนเต็ม 8 บิตที่ไม่ได้ลงนามจำนวนสองชุดโดยมีองค์ประกอบเดียวในแต่ละรายการ ค่าของอาร์เรย์แรกคือ 60 ในขณะที่ค่าของอาร์เรย์ที่สองคือ 100

เลขคณิตของเรากำหนดว่าการลบควรได้ค่า -40 แต่ OpenCV จัดการการตัดให้เราอีกครั้ง เราพบว่ามีการตัดค่าเป็น 0 ผลลัพธ์ของเราด้านล่างแสดงให้เห็นสิ่งนี้:

เลขคณิต พาย

ขั้นต่ำของ 0 : [ [ 0 ] ]

ใช้ cv2 ลบ 100 จาก 60 ลบ ทำให้เกิดค่า 0

แต่จะเกิดอะไรขึ้นหากเราใช้ NumPy แทน OpenCV เพื่อดำเนินการคำนวณ

สาย 38 และ 39 แก้ไขปัญหานี้

ขั้นแรก กำหนดอาร์เรย์ NumPy จำนวนเต็ม 8 บิต 8 บิตสองชุดที่มีองค์ประกอบเดียว ค่าของอาร์เรย์แรกคือ 201 ในขณะที่ค่าของอาร์เรย์ที่สองคือ 100 การบวกของเราจะถูกตัดแต่ง และจะส่งกลับค่า 255 ถ้าเราใช้ฟังก์ชัน cv2.add

ในทางกลับกัน NumPy 'ล้อมรอบ' และใช้เลขคณิตแบบโมดูโลแทนการตัด NumPy ล้อมรอบเป็นศูนย์เมื่อถึงค่า 255 แล้วเริ่มนับต่อไปจนกว่าจะถึง 100 ก้าว สิ่งนี้ได้รับการยืนยันโดยเอาต์พุตบรรทัดแรกซึ่งแสดงไว้ด้านล่าง:

เลขคณิต พาย
ห่อรอบ ๆ: [ สี่ห้า ]

จากนั้น มีการกำหนดอาร์เรย์ NumPy อีกสองอาร์เรย์ หนึ่งมีค่า 50 และอีกอันหนึ่งมีค่าเป็น 100 การลบนี้จะถูกตัดแต่งโดยเมธอด cv2.subtract เพื่อส่งคืนผลลัพธ์เป็น 0 แต่เราทราบดีว่าแทนที่จะตัด NumPy จะดำเนินการ โมดูโล่เลขคณิต แต่กระบวนการโมดูโลจะวนรอบและเริ่มนับถอยหลังจาก 255 เมื่อถึง 0 ระหว่างการลบ เราสามารถเห็นสิ่งนี้ได้จากผลลัพธ์ต่อไปนี้:

เลขคณิต พาย

ห่อรอบ ๆ: [ 207 ]

อีกครั้ง เอาต์พุตเทอร์มินัลของเราแสดงให้เห็นถึงความแตกต่างระหว่างการตัดและการพันรอบ:

จำเป็นอย่างยิ่งที่จะต้องคำนึงถึงผลลัพธ์ที่คุณต้องการเมื่อคำนวณเลขจำนวนเต็ม คุณต้องการตัดค่าใด ๆ ที่อยู่นอกช่วง [0, 255] หรือไม่ ใช้เทคนิคการคำนวณรูปภาพในตัวของ OpenCV หลังจากนั้น

คุณต้องการให้ค่าล้อมรอบหากค่าเหล่านั้นอยู่นอกช่วงของ [0, 255] และการดำเนินการทางคณิตศาสตร์แบบโมดูลัสหรือไม่ จากนั้น อาร์เรย์ NumPy จะถูกเพิ่มและลบตามปกติ

สาย 48 กำหนดอาร์เรย์ NumPy หนึ่งมิติที่มีขนาดเดียวกับรูปภาพของเรา เราตรวจสอบอีกครั้งว่าประเภทข้อมูลของเราเป็นจำนวนเต็ม 8 บิตที่ไม่ได้ลงนาม เราเพียงแค่คูณเมทริกซ์ของค่าหนึ่งหลักด้วย 101 เพื่อเติมด้วยค่า 101 แทนที่จะเป็น 1 สุดท้าย เราใช้ฟังก์ชัน cv2.add เพื่อเพิ่มเมทริกซ์ 100 ของเราลงในภาพต้นฉบับ ซึ่งจะเพิ่มความเข้มของแต่ละพิกเซลขึ้น 101 ในขณะเดียวกันก็ช่วยให้แน่ใจว่าค่าใดๆ ที่พยายามเกิน 255 จะถูกตัดให้อยู่ในช่วง [0, 255]

สังเกตว่าภาพสว่างขึ้นอย่างเห็นได้ชัดและดู 'ซีดจาง' กว่าภาพต้นฉบับอย่างไร เนื่องจากเรากำลังขับเคลื่อนพิกเซลไปสู่สีที่สว่างขึ้นโดยเพิ่มความเข้มของพิกเซลขึ้น 101

ในการลบ 60 ออกจากแต่ละพิกเซลของความเข้มของภาพ อันดับแรก เราจะสร้างอาร์เรย์ NumPy ที่สองบนบรรทัดที่ 54 ซึ่งเติมด้วย 60s

ผลลัพธ์ของการลบนี้จะอธิบายไว้ในภาพต่อไปนี้:

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

4. การพลิกภาพ

เช่นเดียวกับการหมุน การพลิกภาพข้ามแกน x หรือ y เป็นอีกทางเลือกหนึ่งที่ OpenCV นำเสนอ แม้ว่าจะไม่ได้ใช้การพลิกบ่อยนัก แต่การรู้ว่ามีประโยชน์อย่างเหลือเชื่อด้วยเหตุผลหลายประการที่คุณอาจไม่เห็นในทันที

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

แล้วเราจะทำอย่างไร?

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

ตัวอย่างนี้อาจดูงี่เง่าและประดิษฐ์ขึ้น แต่ก็ไม่เป็นเช่นนั้น การพลิกเป็นกลยุทธ์โดยเจตนาที่ใช้โดยอัลกอริธึมการเรียนรู้เชิงลึกที่แข็งแกร่งเพื่อสร้างข้อมูลเพิ่มเติมในระหว่างขั้นตอนการฝึกอบรม

เป็นที่ชัดเจนว่าวิธีการประมวลผลภาพที่คุณเรียนรู้ในโมดูลนี้ใช้เป็นรากฐานสำหรับระบบวิชันซิสเต็มของคอมพิวเตอร์ที่ใหญ่ขึ้น

วัตถุประสงค์:

ใช้ cv2.flip คุณจะได้เรียนรู้วิธีการพลิกภาพทั้งแนวนอนและแนวตั้งในเซสชั่นนี้

การพลิกคือการจัดการภาพครั้งต่อไปที่เราจะศึกษา แกน x และ y ของภาพสามารถกลับด้านหรือทั้งสองอย่างได้ ก่อนที่เราจะดำดิ่งสู่การเข้ารหัส วิธีที่ดีที่สุดคือดูผลลัพธ์ของการพลิกภาพก่อน ดูภาพที่พลิกแนวนอนในภาพต่อไปนี้:


สังเกตว่าภาพต้นฉบับของเราอยู่ทางด้านซ้ายอย่างไร และภาพถูกสะท้อนในแนวนอนทางด้านขวาอย่างไร

เริ่มต้นด้วยการสร้างไฟล์ใหม่ชื่อ flipping.py .

คุณได้เห็นตัวอย่างการพลิกภาพแล้ว ลองตรวจสอบรหัสกัน:

# หลาม flipping.py --image quirrel.jpg

# การนำเข้าแพ็คเกจที่จำเป็น

นำเข้า หาเรื่อง

นำเข้า cv2

# สร้างวัตถุของตัวแยกวิเคราะห์อาร์กิวเมนต์และแยกวิเคราะห์อาร์กิวเมนต์

apObj = หาเรื่อง อาร์กิวเมนต์ Parser ( )

apObj add_argument ( '-ผม' , '--ภาพ' , ที่จำเป็น = จริง , ช่วย = 'เส้นทางภาพ' )

การโต้แย้ง = ของใคร ( apObj parse_args ( ) )

ภาพ = cv2 ฉันอ่าน ( การโต้แย้ง [ 'ภาพ' ] )

cv2 แสดง ( 'ต้นฉบับ' , ภาพ )

#พลิกภาพในแนวนอน

ภาพพลิก = cv2 พลิก ( ภาพ , 1 )

cv2 แสดง ( 'พลิกภาพในแนวนอน' , ภาพพลิก )

#พลิกภาพในแนวตั้ง

ภาพพลิก = cv2 พลิก ( ภาพ , 0 )

cv2 แสดง ( 'พลิกภาพในแนวตั้ง' , ภาพพลิก )

# ภาพพลิกตามแกนทั้งสอง

ภาพพลิก = cv2 พลิก ( ภาพ , - 1 )

cv2 แสดง ( 'พลิกแนวนอนและแนวตั้ง' , ภาพพลิก )

cv2 รอคีย์ ( 0 )

ขั้นตอนที่เราใช้เพื่อนำเข้าแพ็กเกจ แยกวิเคราะห์อินพุต และโหลดอิมเมจจากดิสก์ได้รับการจัดการใน l ใน 1 ถึง 12 .

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

ค่ารหัสพลิกเป็น 1 หมายความว่าเราจะหมุนรูปภาพรอบแกน y เพื่อพลิกตามแนวนอน ( บรรทัดที่ 15 ). ถ้าเราระบุรหัสพลิกเป็น 0 เราต้องการหมุนภาพรอบแกน x ( บรรทัดที่ 19 ). รหัสพลิกลบ ( สาย 23 ) หมุนภาพทั้งสองแกน

หนึ่งในตัวอย่างที่ง่ายที่สุดในเรื่องนี้คือการพลิกภาพ ซึ่งเป็นพื้นฐาน

ต่อไป เราจะพูดถึงการครอบตัดรูปภาพและใช้ชิ้นส่วนอาร์เรย์ NumPy เพื่อแยกส่วนรูปภาพเฉพาะ

5. การครอบตัดรูปภาพ

การครอบตัดตามชื่อหมายถึง เป็นกระบวนการของการเลือกและลบพื้นที่ที่สนใจ (หรือเรียกสั้นๆ ว่า ROI) ซึ่งเป็นพื้นที่ของภาพที่เราสนใจ

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

เป้าหมาย: เป้าหมายหลักของเราคือทำความคุ้นเคยและใช้งาน NumPy array slicing เพื่อครอบตัดพื้นที่จากรูปภาพ

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

สร้างไฟล์ใหม่ชื่อ crop.py ให้เปิดและเพิ่มรหัสต่อไปนี้:

#หลามcrop.py

# การนำเข้าแพ็คเกจที่จำเป็น

นำเข้า cv2

# โหลดภาพและแสดงบนหน้าจอ

ภาพ = cv2 ฉันอ่าน ( 'squirrel.jpg' )

พิมพ์ ( ภาพ. รูปร่าง )

cv2 แสดง ( 'ต้นฉบับ' , ภาพ )

# ชิ้นส่วนอาร์เรย์ NumPy ใช้เพื่อตัดแต่งภาพอย่างรวดเร็ว

# เราจะครอบตัดหน้ากระรอกออกจากภาพ

หน้ากระรอก = ภาพ [ 35 : 90 , 35 : 100 ]

cv2 แสดง ( 'หน้ากระรอก' , หน้ากระรอก )

cv2 รอคีย์ ( 0 )

#และตอนนี้เราจะครอบตัดทั้งตัว

#ของกระรอก

ตัวกระรอก = ภาพ [ 35 : 148 , 23 : 143 ]

cv2 แสดง ( 'ร่างกระรอก' , ตัวกระรอก )

cv2 รอคีย์ ( 0 )

เราจะแสดงการครอบตัดใน Python และ OpenCV โดยใช้รูปภาพที่เราโหลดจากดิสก์ บรรทัดที่ 5 และ 6 .

ภาพต้นฉบับที่เราจะครอบตัด

เราใช้เทคนิคการครอบตัดขั้นพื้นฐานเท่านั้น เราตั้งเป้าที่จะแยกหน้ากระรอกและตัวกระรอกออกจากบริเวณรอบๆ

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

เราสามารถระบุใบหน้าในภาพได้ด้วยโค้ดเพียงบรรทัดเดียว บรรทัดที่ 13 , ในการแยกส่วนสี่เหลี่ยมผืนผ้าของรูปภาพ เริ่มต้นที่ (35, 35) เราจัดเตรียมชิ้นส่วนอาร์เรย์ NumPy (90, 100) อาจดูสับสนที่เราป้อนการครอบตัดด้วยดัชนีในลำดับความสูง-หนึ่งและความกว้าง-วินาทีที่เราทำ แต่โปรดจำไว้ว่า OpenCV จัดเก็บรูปภาพเป็นอาร์เรย์ NumPy ดังนั้น เราต้องป้อนค่าสำหรับแกน y ก่อนแกน x

NumPy ต้องการสี่ดัชนีต่อไปนี้เพื่อดำเนินการครอบตัดของเรา:

เริ่มต้น y: พิกัด y ที่จุดเริ่มต้น สำหรับตัวอย่างนี้ เราเริ่มต้นที่ y=35

จบ y: พิกัด y ในตอนท้าย การครอบตัดของเราจะหยุดลงเมื่อ y = 90

เริ่ม x: จุดเริ่มต้นของชิ้น x พิกัด การครอบตัดเริ่มต้นที่ x=35

จบ x: พิกัดแกน x ส่วนท้ายของสไลซ์ ที่ x=100 ชิ้นของเราจะเสร็จแล้ว

ในทำนองเดียวกัน เราครอบตัดบริเวณ (23, 35) และ (143, 148) จากภาพต้นฉบับเพื่อแยกเนื้อหาทั้งหมดออกจากภาพบน บรรทัดที่ 19 .

คุณสามารถสังเกตได้ว่ารูปภาพถูกครอบตัดเพื่อแสดงเฉพาะส่วนของร่างกายและใบหน้าเท่านั้น

6. การปรับขนาดรูปภาพ

กระบวนการเพิ่มหรือลดความกว้างและความสูงของรูปภาพเรียกว่าการปรับขนาดหรือการปรับขนาด ควรพิจารณาสัดส่วนภาพ ซึ่งเป็นสัดส่วนของความกว้างต่อความสูงของภาพเมื่อปรับขนาดภาพ การละเลยอัตราส่วนกว้างยาวอาจส่งผลให้ภาพที่ได้รับการปรับขนาดมีลักษณะบีบอัดและบิดเบี้ยว:

ภาพเริ่มต้นของเราอยู่ทางด้านซ้าย ทางด้านขวา คุณจะเห็นภาพสองภาพที่ได้รับการปรับขนาดโดยไม่รักษาอัตราส่วนภาพ ทำให้สัดส่วนของความกว้างต่อความสูงของภาพบิดเบี้ยว เมื่อปรับขนาดรูปภาพ โดยทั่วไปคุณควรคำนึงถึงอัตราส่วนภาพ

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

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

เรามีภาพต้นฉบับของเราทางด้านซ้าย รูปภาพถูกลดขนาดลงเหลือครึ่งหนึ่งของขนาดดั้งเดิมที่กึ่งกลาง แต่นอกเหนือจากนั้น ไม่มีการสูญเสีย 'คุณภาพ' ของรูปภาพ อย่างไรก็ตาม ขนาดของรูปภาพได้รับการปรับปรุงอย่างมากทางด้านขวา ตอนนี้ปรากฏเป็น 'ระเบิด' และ 'พิกเซล'

ดังที่ฉันได้กล่าวไว้ก่อนหน้านี้ โดยปกติแล้วคุณจะต้องการลดขนาดของภาพแทนที่จะเพิ่มขนาด ด้วยการลดขนาดภาพ เราวิเคราะห์พิกเซลน้อยลงและต้องจัดการกับ 'สัญญาณรบกวน' น้อยลง ซึ่งทำให้อัลกอริทึมการประมวลผลภาพรวดเร็วและแม่นยำยิ่งขึ้น

การแปลและการหมุนเป็นการแปลงภาพสองแบบที่กล่าวถึงในตอนนี้ ตอนนี้เราจะตรวจสอบวิธีการปรับขนาดรูปภาพ

ไม่น่าแปลกใจที่เราจะปรับขนาดภาพของเราโดยใช้วิธีการ cv2.resize ดังที่ฉันได้ระบุไว้ก่อนหน้านี้ เราต้องพิจารณาสัดส่วนภาพของรูปภาพเมื่อใช้วิธีนี้ แต่ก่อนที่เราจะลงลึกไปในรายละเอียด ผมขอยกตัวอย่างให้คุณฟังก่อน:

# หลาม resize.py --image กระรอก.jpg

# การนำเข้าแพ็คเกจที่จำเป็น

นำเข้า หาเรื่อง

นำเข้า cv2

# สร้างวัตถุของตัวแยกวิเคราะห์อาร์กิวเมนต์และแยกวิเคราะห์อาร์กิวเมนต์

apObj = หาเรื่อง อาร์กิวเมนต์ Parser ( )

apObj add_argument ( '-k' , '--ภาพ' , ที่จำเป็น = จริง , ช่วย = 'เส้นทางภาพ' )

ข้อโต้แย้ง = ของใคร ( apObj parse_args ( ) )

# โหลดภาพและแสดงบนหน้าจอ

ภาพ = cv2 ฉันอ่าน ( ข้อโต้แย้ง [ 'ภาพ' ] )

cv2 แสดง ( 'ต้นฉบับ' , ภาพ )

# เพื่อป้องกันไม่ให้ภาพบิดเบี้ยว อัตราส่วนกว้างยาว

# ต้องได้รับการพิจารณาหรือพิการ ดังนั้นเราจึงเข้าใจว่าอะไร

# อัตราส่วนของภาพใหม่กับภาพปัจจุบัน

# มาสร้างความกว้างของภาพใหม่ของเรา 160 พิกเซล

ด้าน = 160.0 / ภาพ. รูปร่าง [ 1 ]

มิติ = ( 160 , นานาชาติ ( ภาพ. รูปร่าง [ 0 ] * ด้าน ) )

# บรรทัดนี้จะแสดงการดำเนินการปรับขนาดจริง

ปรับขนาดภาพ = cv2 ปรับขนาด ( ภาพ , มิติ , การแก้ไข = cv2 INTER_AREA )

cv2 แสดง ( 'ปรับขนาดความกว้างของภาพ' , ปรับขนาดภาพ )

# ถ้าเราต้องการเปลี่ยนความสูงของภาพล่ะ? - ใช้

# หลักการเดียวกัน เราสามารถคำนวณอัตราส่วนภาพตาม

#ความสูงมากกว่าความกว้าง มาทำสเกลกัน

# ความสูงของภาพ 70 พิกเซล

ด้าน = 70.0 / ภาพ. รูปร่าง [ 0 ]

มิติ = ( นานาชาติ ( ภาพ. รูปร่าง [ 1 ] * ด้าน ) , 70 )

#ทำการปรับขนาด

ปรับขนาดภาพ = cv2 ปรับขนาด ( ภาพ , มิติ , การแก้ไข = cv2 INTER_AREA )

cv2 แสดง ( 'ปรับขนาดความสูงของภาพ' , ปรับขนาดภาพ )

cv2 รอคีย์ ( 0 )

บรรทัดที่ 1-14 หลังจากนำเข้าแพ็คเกจของเราและกำหนดค่าตัวแยกวิเคราะห์อาร์กิวเมนต์แล้ว เราจะโหลดและแสดงรูปภาพของเรา

บรรทัดที่ 20 และ 21: การเข้ารหัสที่เกี่ยวข้องจะเริ่มต้นในบรรทัดเหล่านี้ . ต้องคำนึงถึงอัตราส่วนกว้างยาวของภาพในขณะที่ปรับขนาด สัดส่วนระหว่างความกว้างและความสูงของรูปภาพเรียกว่าอัตราส่วนกว้างยาว

สูงกว้าง คืออัตราส่วนภาพ

หากเราไม่คำนึงถึงอัตราส่วนภาพ ผลลัพธ์ของการปรับขนาดของเราจะผิดเพี้ยนไป

บน สาย 20 การคำนวณอัตราส่วนที่ปรับขนาดเสร็จแล้ว เราระบุความกว้างของรูปภาพใหม่เป็น 160 พิกเซลในโค้ดบรรทัดนี้ เราเพียงแค่กำหนดอัตราส่วนของเรา (aspectratio) เป็นความกว้างใหม่ (160 พิกเซล) หารด้วยความกว้างเดิม ซึ่งเราเข้าถึงโดยใช้รูปภาพ เพื่อคำนวณอัตราส่วนของความสูงใหม่ต่อความสูงเดิม รูปร่าง[1].

มิติใหม่ของภาพบน สาย 21 สามารถคำนวณได้เมื่อเรารู้อัตราส่วนของเราแล้ว อีกครั้ง รูปภาพใหม่จะมีความกว้าง 160 พิกเซล หลังจากคูณความสูงเดิมด้วยอัตราส่วนของเราแล้วแปลงผลลัพธ์เป็นจำนวนเต็ม ความสูงจะถูกคำนวณ เราสามารถรักษาอัตราส่วนเดิมของภาพได้โดยดำเนินการนี้

สาย 24 เป็นที่ที่ภาพถูกปรับขนาดจริงๆ รูปภาพที่เราต้องการปรับขนาดคืออาร์กิวเมนต์แรก และอาร์กิวเมนต์ที่สองคือขนาดที่เราคำนวณสำหรับรูปภาพใหม่ วิธีการแก้ไขของเราซึ่งเป็นอัลกอริทึมสำหรับการปรับขนาดภาพจริงเป็นพารามิเตอร์สุดท้าย

ในที่สุดเมื่อ สาย 25 เราแสดงภาพที่ปรับขนาดของเรา

เรากำหนดอัตราส่วนของเราใหม่ (aspectratio) บน สาย 31 . ความสูงของภาพใหม่ของเราจะอยู่ที่ 70 พิกเซล เราหาร 70 ด้วยความสูงเดิมเพื่อให้ได้อัตราส่วนความสูงต่อความสูงเดิมใหม่

ต่อไป เรากำหนดขนาดของรูปภาพใหม่ รูปภาพใหม่จะมีความสูง 70 พิกเซล ซึ่งทราบกันดีอยู่แล้ว เราสามารถรักษาอัตราส่วนเดิมของภาพได้อีกครั้งโดยการคูณความกว้างเดิมด้วยอัตราส่วนเพื่อให้ได้ความกว้างใหม่

จากนั้นภาพจะถูกปรับขนาดจริง สาย 35 และจะแสดงบน สาย 36.

ที่นี่ เราจะเห็นว่าเราได้ลดความกว้างและความสูงของภาพต้นฉบับของเราในขณะที่รักษาอัตราส่วนไว้ รูปภาพของเราอาจดูบิดเบี้ยวหากไม่รักษาอัตราส่วนภาพไว้

บทสรุป

ในบล็อกนี้ เราได้ศึกษาแนวคิดพื้นฐานในการประมวลผลภาพแบบต่างๆ เราได้เห็นการแปลรูปภาพด้วยความช่วยเหลือของแพ็คเกจ OpenCV เราได้เห็นวิธีการเลื่อนภาพขึ้น ลง ขวา และซ้าย วิธีการเหล่านี้มีประโยชน์มากเมื่อเราสร้างชุดข้อมูลของรูปภาพที่คล้ายกันเพื่อให้เป็นชุดข้อมูลการฝึกอบรม ดังนั้นเครื่องจะมองเห็นรูปภาพที่แตกต่างกันแม้ว่าจะเหมือนกันก็ตาม บทความนี้ยังสอนวิธีหมุนภาพรอบจุดใดๆ ในปริภูมิคาร์ทีเซียนโดยใช้เมทริกซ์การหมุน จากนั้นคุณก็ค้นพบวิธีที่ OpenCV หมุนภาพโดยใช้เมทริกซ์นี้ และเห็นภาพหมุนภาพสองสามภาพ

การดำเนินการเลขคณิตภาพพื้นฐาน (แต่มีนัยสำคัญ) สองรายการของการบวกและการลบได้รับการตรวจสอบในส่วนนี้ อย่างที่คุณเห็น การเพิ่มและการลบเมทริกซ์พื้นฐานคือการคำนวณทางคณิตศาสตร์ทั้งหมดที่เกี่ยวข้อง

นอกจากนี้ เราใช้ OpenCV และ NumPy เพื่อตรวจสอบลักษณะเฉพาะของเลขคณิตรูปภาพ ต้องคำนึงถึงข้อจำกัดเหล่านี้ มิฉะนั้นคุณอาจเสี่ยงที่จะเจอผลลัพธ์ที่ไม่คาดคิดเมื่อดำเนินการทางคณิตศาสตร์กับรูปภาพของคุณ

สิ่งสำคัญคือต้องจำไว้ว่าแม้ว่า NumPy จะดำเนินการโมดูลัสและ 'ล้อมรอบ' การบวกและการลบของ OpenCV จะตัดค่าที่เกินช่วง [0, 255] เพื่อให้พอดีกับช่วง เมื่อพัฒนาแอปพลิเคชันคอมพิวเตอร์วิทัศน์ของคุณเอง การจดจำสิ่งนี้จะช่วยคุณในการหลีกเลี่ยงการตามล่าหาบั๊กที่ยุ่งยาก

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

เรายังได้เรียนรู้วิธีใช้ OpenCV เพื่อปรับขนาดรูปภาพ สิ่งสำคัญคือต้องพิจารณาทั้งวิธีการแก้ไขที่คุณใช้และอัตราส่วนกว้างยาวของภาพต้นฉบับเมื่อปรับขนาด เพื่อไม่ให้ผลลัพธ์ดูผิดเพี้ยน

สุดท้าย สิ่งสำคัญคือต้องจำไว้ว่าหากคุณภาพของภาพเป็นปัญหา คุณควรเปลี่ยนจากภาพที่ใหญ่ขึ้นเป็นภาพที่เล็กลงเสมอ ในกรณีส่วนใหญ่ การขยายภาพจะสร้างสิ่งประดิษฐ์และลดคุณภาพของภาพ