ค้นหาพิกเซลสีดำแรกในทุกแถวด้วย ImageMagick

สำหรับทุกแถวในรูปภาพ ฉันต้องการค้นหาพิกเซลสีดำแรก (หรือพิกเซลแรกที่ไม่ใช่สีขาว) ในแถวนั้น ตัวอย่างเช่น สำหรับรูปภาพลักษณะนี้:

ป้อนคำอธิบายรูปภาพที่นี่

ฉันคาดหวังผลลัพธ์เช่น:

0
1
0

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


person pjreddie    schedule 05.03.2015    source แหล่งที่มา
comment
แล้วคุณต้องการคืนอะไรให้กับแถวของพิกเซลสีขาวเท่านั้น?   -  person Kurt Pfeifle    schedule 05.03.2015
comment
คำถามนั้นอยู่ที่ปลายลิ้นของฉัน :-)   -  person Mark Setchell    schedule 05.03.2015


คำตอบ (2)


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

1. พื้นฐาน

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

convert wizard: textwizard.txt

(wizard: เป็นอิมเมจในตัวสำหรับการติดตั้ง ImageMagick ทั้งหมดเพื่อการทดสอบ)

ใช่ มันง่ายมาก! ขอ "รูปแบบ" รูปภาพนี้โดยเพิ่มส่วนต่อท้าย .txt ผลลัพธ์:

# ImageMagick pixel enumeration: 480,640,255,srgb
0,0: (255,255,255)  #FFFFFF  white
1,0: (255,255,255)  #FFFFFF  white
2,0: (255,255,255)  #FFFFFF  white
[....]
47,638: (246,247,249)  #F6F7F9  srgb(246,247,249)
48,638: (246,247,249)  #F6F7F9  srgb(246,247,249)
47,639: (236,235,236)  #ECEBEC  srgb(236,235,236)
48,639: (230,228,218)  #E6E4DA  srgb(230,228,218)
[....]
476,639: (255,255,255)  #FFFFFF  white
477,639: (255,255,255)  #FFFFFF  white
478,639: (255,255,255)  #FFFFFF  white
479,639: (255,255,255)  #FFFFFF  white

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

# ImageMagick pixel enumeration: 480,640,255,srgb

มันหมายความว่า:

  • ภาพมีความกว้าง 480 พิกเซล
  • ภาพมีความสูง 640 พิกเซล
  • รูปภาพใช้ช่วง 0-255 สำหรับข้อมูลสีต่อช่อง (ซึ่งเทียบเท่ากับความลึกของสี 8 บิต)
  • รูปภาพถูกสร้างขึ้นในพื้นที่สี sRGB

บรรทัดอื่นๆ ประกอบด้วย 4 คอลัมน์:

  1. คอลัมน์แรกในรูปแบบ (N,M) ระบุตำแหน่งที่แน่นอนของพิกเซลตามลำดับเป็น (row_number,column_number) (ดัชนีสำหรับหมายเลขแถวและคอลัมน์เป็นแบบศูนย์ -- แถวที่ 1 ระบุเป็น 0, ลำดับที่ 2 เป็น 1)
  2. อีกสามคอลัมน์ที่เหลือซ้ำซ้อน แต่ละคอลัมน์เก็บข้อมูลเดียวกันทุกประการ แต่ละคอลัมน์ใช้สัญกรณ์ที่แตกต่างกัน: ค่าสีที่แน่นอนสำหรับพิกเซลที่กำหนดในคอลัมน์ 1 (คอลัมน์สุดท้ายจะใช้ชื่อที่มนุษย์สามารถอ่านได้หาก ImageMagick รู้จัก สำหรับค่าสีนั้น...)

ตามหมายเหตุด้านข้าง: คุณสามารถใช้การแสดงข้อความของรูปภาพต้นฉบับ (โดยมีหรือไม่มีการแก้ไขเพิ่มเติมบางอย่าง) เพื่อสร้างรูปภาพจริงขึ้นมาใหม่:

convert textwizard.txt wizard.jpg

2. เลือกแถวที่ต้องการ

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

image.png[WIDTHxHEIGHT+X_OFFSET+Y_OFFSET]

ดังนั้นหากต้องการเลือกเฉพาะแถว คุณสามารถตั้งค่า HEIGHT เป็น 1 ได้ หากต้องการให้แถวใดแถวหนึ่งสมบูรณ์ ให้ตั้งค่า X-OFFSET เป็น 0 หากต้องการรับแถวที่ต้องการ ให้ตั้งค่า Y-OFFSET ตามนั้น

เพื่อให้ได้ค่า (สำหรับอิมเมจบิวด์อิน wizard: ที่ใช้ด้านบน) สำหรับแถวที่มีดัชนี 47 เราสามารถทำได้:

convert wizard:[640x1+0+47] row47.txt

cat row47.txt
 # ImageMagick pixel enumeration: 480,1,255,srgb
 0,0: (255,255,255)  #FFFFFF  white
 1,0: (255,255,255)  #FFFFFF  white
 2,0: (255,255,255)  #FFFFFF  white
 [....]
 428,0: (82,77,74)     #524D4A  srgb(82,77,74)
 429,0: (169,167,168)  #A9A7A8  srgb(169,167,168)
 430,0: (232,231,228)  #E8E7E4  srgb(232,231,228)
 432,0: (246,247,249)  #F6F7F9  srgb(246,247,249)
 [....]
 476,0: (255,255,255)  #FFFFFF  white
 477,0: (255,255,255)  #FFFFFF  white
 478,0: (255,255,255)  #FFFFFF  white
 479,0: (255,255,255)  #FFFFFF  white

หากคุณไม่ต้องการเอาต์พุตข้อความในไฟล์ แต่พิมพ์บนช่องเอาต์พุตมาตรฐาน คุณสามารถทำได้ดังนี้:

convert wizard:[480x1+0+47] txt:-

3. เย็บทั้งหมดเข้าด้วยกัน

จากข้อมูลข้างต้น แนวทางที่สามารถนำมาใช้กับงานนี้ได้มีความชัดเจน:

  1. วนซ้ำแถวพิกเซลทั้งหมดของรูปภาพ
  2. ส่งออกค่าสีของแต่ละพิกเซลเป็นข้อความ
  3. มองหาพิกเซลแรกที่ไม่ใช่สีขาวและเก็บข้อมูลตำแหน่งไว้

4. สคริปต์ที่เป็นไปได้ (OS X, Linux, Unix)

นี่คือส่วนหลักของสคริปต์ Bash ที่สามารถใช้ได้:

# Define some image specific variables (width, height, ...)
image=${1}
number_of_columns=$(identify -format '%W' ${image}) 
width=${number_of_columns}                        # just an alias
number_of_rows=$(identify -format '%H' ${image})
height=${number_of_rows}                          # just an alias
max_of_indices=$(( ${height} -1 ))

# Loop through all rows and grep for first non-white pixel
for i in $(seq 0 ${max_of_indices}); do
   echo -n "Row ${i} :  " ;
   convert ${image}[${width}x1+0+${i}] txt:- \
     | grep -v enumeration                   \
     | grep -v '#FFFFFF' -m 1                \
   || echo "All WHITE pixels in row!"  
done

-v white จะยกเลิกการเลือกบรรทัดทั้งหมดที่มีสตริง white พารามิเตอร์ -m 1 จะคืนค่าการจับคู่สูงสุด 1 รายการ (เช่น รายการแรก)

มันจะช้าแต่จะทำงาน

person Kurt Pfeifle    schedule 05.03.2015
comment
ขอบคุณ ฉันใช้แนวทางที่คล้ายกัน ฉันใช้ python แทนเพราะฉันได้ทำสิ่งอื่นๆ มากมายอยู่ที่นั่นแล้ว การประมวลผลข้อความเป็นวิธีการที่แน่นอนในการดำเนินการนี้ - person pjreddie; 05.03.2015

ฉันจะทำสิ่งนี้โดยใช้รูปแบบกระดานหมากรุกในตัว:

convert -size 100x100 pattern:checkerboard -auto-level board.png

ป้อนคำอธิบายรูปภาพที่นี่

#!/bin/bash
convert wizard: txt: | awk -F'[,: ]' '
   /^#/ || /#FFFFFF/ {next}
   !($2 in fb)       {fb[$2]=$1}
   END               {r=$2;for(i=0;i<=r;i++){if(i in fb)print i,fb[i]; else print i,"-1"}}'

-F[,: ] บอกให้ awk แยกคำในบรรทัดด้วยลูกน้ำ ทวิภาค หรือช่องว่าง ซึ่งจะช่วยให้ฉันเข้าใจแถวและคอลัมน์ที่จุดเริ่มต้นของแต่ละบรรทัด บรรทัดที่มี /^#/ จะข้ามความคิดเห็นในบรรทัดแรกของเอาต์พุตข้อความ ImageMagick และบรรทัดทั้งหมดที่มี white หรือ #FFFFFF

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

ในตอนท้าย ภายใน END{} ฉันดำเนินการผ่าน fb[] โดยพิมพ์แถวและดัชนีทั้งหมดของพิกเซลสีดำแรกในแถวเหล่านั้น โปรดทราบว่าฉันส่งออก -1 แทนที่องค์ประกอบที่ไม่ได้กำหนด (เช่น องค์ประกอบที่ไม่มีพิกเซลที่ไม่ใช่สีขาว) - ขอบคุณ @KurtPfeifle สำหรับคำแนะนำ

person Mark Setchell    schedule 05.03.2015
comment
มันใช้ได้กับรูปภาพประเภทที่ไม่ใช่กระดานหมากรุกหรือเปล่า มาร์ค? - person Kurt Pfeifle; 05.03.2015
comment
@KurtPfeifle ตอนนี้ทำได้แล้ว - ขอบคุณ! ฉันทดสอบกับ convert rose: -threshold 50% -flop txt: ... - person Mark Setchell; 05.03.2015
comment
ทดสอบกับ wizard: มาร์ค ของคุณให้ผลลัพธ์ที่แตกต่างไปจากของฉันอย่างสิ้นเชิง คุณส่งคืนเพียง XXX 0 สำหรับฉัน - person Kurt Pfeifle; 05.03.2015
comment
หากฉันสร้างไฟล์ด้วย convert rose: -threshold 50% -flop rose-bw-flopped.png นี่คืออิมเมจ 70x46 แสดงว่าสคริปต์ของคุณไม่ทำงาน - person Kurt Pfeifle; 05.03.2015
comment
อ๊ะ - ฉันมี inverted วัน! ทุกอย่างเริ่มต้นเมื่อ OP ขอพิกเซล สีดำแรก (หรือไม่ใช่สีขาว)... ฉันคิดว่ามันถูกต้องแล้ว ขอบคุณ - person Mark Setchell; 05.03.2015
comment
แต่มันใช้งานไม่ได้กับไฟล์อินพุต ใด ๆ (ยัง) - เฉพาะสำหรับกระดานหมากรุกที่สร้างขึ้นเองเท่านั้น ... :-) BTW ฉันก็กลับด้าน s.th ด้วย ก่อนหน้านี้ - สลับแถวและคอลัมน์ในคำตอบของฉันเวอร์ชันก่อนหน้า ;-) - person Kurt Pfeifle; 05.03.2015
comment
ฉันดูดโค้ด sed/awk จริง ๆ ทันทีที่มันไปไกลกว่างานพื้นฐานที่สุด และไม่เคยฝันที่จะทำสิ่งเหมือนที่คุณทำในคำตอบนี้ -- บางทีนั่นอาจเป็นเหตุผลว่าทำไมฉันถึงใช้วิธีแก้ปัญหาของคุณไม่ได้? (ความคาดหวังของฉันคือมันจะทำงานกับรูปภาพ ใดก็ได้ ไม่ใช่แค่สีดำ+ขาว) ถ้าฉันเปลี่ยน board.png ในสคริปต์ awk ของคุณเป็นรูปภาพอื่น ๆ ของฉัน และโซลูชันของคุณให้ผลลัพธ์ที่แตกต่างกันมาก ฉันคิดว่าสคริปต์ของคุณยังมีข้อบกพร่องอีกประการหนึ่ง: มันจะคืนค่าทั้งหมด 0s แม้จะเป็นรูปภาพกระดานหมากรุกก็ตาม - person Kurt Pfeifle; 05.03.2015
comment
@ KurtPfeifle Mmmm ดูเหมือนว่าจะได้ผลสำหรับฉัน -auto-level เป็นสิ่งสำคัญในการทำให้ ผ้าขาวของคุณขาว - ฟังดูเหมือนโฆษณาผงซักฟอก! - person Mark Setchell; 05.03.2015
comment
อย่างที่ฉันบอกไป ฉันคาดหวังวิธีแก้ปัญหาที่จะใช้ได้กับรูปภาพใดๆ ความท้าทายคือการค้นหาพิกเซลแรกที่ไม่ใช่สีขาวในทุกแถว - person Kurt Pfeifle; 05.03.2015
comment
นั่นคือทั้งหมดที่ดีสำหรับวันนี้! ขอบคุณเคิร์ต :-) - person Mark Setchell; 05.03.2015
comment
รหัสที่ดี จะเปลี่ยนให้พิมพ์พิกเซลสีดำสุดท้ายในแต่ละแถวได้อย่างไร ตัวอย่างเช่น 30 2 10 หมายความว่าในแถว 30 พิกเซลสีดำตัวแรกอยู่บนคอลัมน์ 2 และพิกเซลสุดท้ายบนคอลัมน์ 10 ฉันอยากจะบันทึกความแตกต่างไว้ด้วย 10-2=8 ขอบคุณ. - person Sigur; 18.03.2017