แผนภาพสี 24 บิตและแผนภาพสีเทา 8 บิต
ก่อนอื่นมาแนะนำภาพสี 24 บิต ในภาพสี 24 บิตแต่ละพิกเซลจะแสดงด้วยสามไบต์ซึ่งมักจะแสดงเป็น RGB โดยทั่วไปภาพสี 24 บิตจำนวนมากจะถูกเก็บไว้เป็นภาพ 32 บิตและไบต์ส่วนเกินต่อพิกเซลจะถูกเก็บไว้เป็นค่า alpha แสดงข้อมูลอิทธิพลพิเศษ [1]
ในโมเดล RGB ถ้า r = g = b สีแสดงถึงสีเทาซึ่งค่าของ r = g = b เรียกว่าค่าสีเทา ดังนั้นแต่ละพิกเซลของอิมเมจสีเทาจึงต้องใช้เพียงหนึ่งไบต์เพื่อจัดเก็บค่าสีเทา (หรือที่เรียกว่าค่าความเข้มและค่าความสว่าง) และช่วงสีเทาคือ 0-255 [2] สิ่งนี้จะช่วยให้คุณได้ภาพสีเทาของภาพ
หลายวิธีของสีเทา
1. วิธีการส่วนประกอบ: ใช้หนึ่งในสามส่วนประกอบ RGB เป็นค่าสีเทาของแผนที่สีเทา
2. วิธีการที่มีค่าส่วนใหญ่: ใช้ค่าสูงสุดหรือต่ำสุดของส่วนประกอบ RGB ทั้งสามเป็นค่าสีเทาของแผนที่สีเทา
3. วิธีการเฉลี่ย: ใช้ค่าเฉลี่ยของส่วนประกอบ RGB ทั้งสามเป็นค่าสีเทาของกราฟสีเทา
4. วิธีการถ่วงน้ำหนัก: เนื่องจากความไวของสีที่แตกต่างกันของดวงตาของมนุษย์ค่าเฉลี่ยถ่วงน้ำหนักของสามองค์ประกอบ RGB สามารถได้รับภาพสีเทาที่สมเหตุสมผลมากขึ้น สถานการณ์ทั่วไปมีดังนี้: y = 0.30r + 0.59g + 0.11b
[หมายเหตุ] วิธีการถ่วงน้ำหนักใช้ค่าความสว่างของภาพเป็นค่าสีเทาในการคำนวณและใช้โมเดล YUV ใน [3] คุณจะพบว่าผู้เขียนใช้ y = 0.21 * r + 0.71 * g + 0.07 * b ในการคำนวณค่าสีเทา (เห็นได้ชัดว่าผลรวมของน้ำหนักทั้งสามไม่เท่ากับ 1 ซึ่งอาจเป็นความผิดพลาดของผู้เขียน?) ในความเป็นจริงความแตกต่างนี้ควรเกี่ยวข้องกับการแก้ไขแกมม่าหรือไม่ [1]
วิธีการใช้สีเทาในชวา
หากคุณค้นหา "Java ใช้สีเทา" ส่วนใหญ่เป็นวิธีเดียว (รหัส):
โมฆะสาธารณะ public greyimage () พ่น IOException {ไฟล์ไฟล์ = ไฟล์ใหม่ (system.getProperty ("user.dir")+"/test.jpg"); bufferedImage image = imageio.read (ไฟล์); ความกว้าง int = image.getWidth (); ความสูง int = image.getheight (); bufferedImage greyimage = bufferedImage ใหม่ (ความกว้าง, ความสูง, bufferedImage.type_byte_gray); สำหรับ (int i = 0; i <width; i ++) {สำหรับ (int j = 0; j <ความสูง j ++) {int rgb = image.getRgb (i, j); greyimage.setrgb (i, j, rgb); }} ไฟล์ newfile = ไฟล์ใหม่ (system.getProperty ("user.dir")+"/method1.jpg"); Imageio.write (greatimage, "jpg", newfile); -ภาพต้นฉบับของ test.jpg คือ:
แผนภาพสีเทาที่ได้รับโดยใช้วิธีการข้างต้น:
การเห็นภาพสีเทานี้ดูเหมือนจะเป็นไปได้ แต่ถ้าเราใช้ opencv เพื่อให้ได้สีเทาหรือใช้ PIL (Python) คุณจะพบว่าเอฟเฟกต์แตกต่างกันอย่างมาก:
img = cv2.imread ('test.jpg', cv2.imread_color) สีเทา = cv2.cvtcolor (img, cv2.color_bgr2gray) cv2.imwrite ('pythonmethod.jpg', สีเทา) จะเห็นได้อย่างชัดเจนว่ากราฟสีเทาที่ได้รับโดยใช้ opencv (เช่นเดียวกับ PIL) นั้นดีกว่าวิธีการที่ได้รับจากวิธี Java ข้างต้นมากและสามารถดูรายละเอียดได้มากมาย นี่แสดงให้เห็นว่าวิธีการที่ได้รับความนิยมบนอินเทอร์เน็ตนี้มีปัญหาอยู่เสมอ แต่ก็ถูกละเว้น
วิธีการบรรลุสีเทาใน OpenCV
หากคุณได้อ่านหนังสือหรือรหัสที่เกี่ยวข้องกับ opencv คุณอาจรู้ว่า opencv GRAYSCALE ใช้วิธีการถ่วงน้ำหนัก เหตุผลประมาณเพราะเราไม่รู้ว่าทำไมภาพสีเทา opencv จึงดีมาก มีรายละเอียดการประมวลผลอื่น ๆ ที่เราเพิกเฉยหรือไม่?
การตรวจสอบการเดาของเรานั้นง่ายมาก เพียงตรวจสอบการเปลี่ยนแปลงก่อนและหลังค่าพิกเซลเป็นสีเทา คุณสามารถทดสอบได้ดังนี้:
img = cv2.imread ('test.jpg', cv2.imread_color) h, w = img.shape [: 2] สีเทา = cv2.cvtcolor (img, cv2.color_bgr2gray) สำหรับ j ในช่วง (w) IMG [H-1] [W-1] [0: 3]มันเป็นเรื่องยากสำหรับเราที่จะตัดสินพิกเซลมากมายด้านล่าง แต่เราต้องให้ความสนใจกับจุดพิกเซลสุดท้ายและเราสามารถหาเบาะแสได้: ค่า RGB ของจุดพิกเซลสุดท้ายในภาพต้นฉบับคือ 44, 67, 89 และค่าหลังจากสีเทาคือ 71 หากคุณตรวจสอบค่าพิกเซลของภาพที่เป็นสีเทาใน Java มาก่อนคุณจะพบว่าไม่เพียง แต่ค่าพิกเซลจะไม่ตรงกับสูตรนี้ แต่ยังห่างไกลจากกัน
ณ จุดนี้เราเดาว่า OpenCV (รวมถึง PIL) เป็นการใช้งานสีเทาโดยใช้วิธีการถ่วงน้ำหนัก
Java ใช้วิธีการถ่วงน้ำหนักสีเทา
หากวิธีการที่ได้รับความนิยมบนอินเทอร์เน็ตไม่ทำงานเราควรใช้ Java เพื่อให้ได้สีเทาได้อย่างไร? ในความเป็นจริง [3] ประสบความสำเร็จในการประสบความสำเร็จ (หลายวิธี) สีเทา (เพื่อนต่างชาติยังคงมีประสิทธิภาพมากในด้านเทคโนโลยี) และมีเพียงรหัสที่จำเป็นเท่านั้นที่ถูกแยกออกมาที่นี่:
private static int colortorgb (int alpha, int สีแดง, สีเขียว int, int สีน้ำเงิน) {int newPixel = 0; newpixel += alpha; newPixel = newPixel << 8; newpixel += สีแดง; newPixel = newPixel << 8; newpixel += สีเขียว; newPixel = newPixel << 8; newpixel += blue; กลับ Newpixel; } โมฆะคงที่สาธารณะหลัก (สตริง [] args) พ่น IOException {bufferedImage bufferedImage = imageio.read (ไฟล์ใหม่ (System.getProperty ("user.dir" + "/test.jpg"); bufferedImage (bufferediGhe.getHegheTh สำหรับ (int i = 0; i <bufferedimage.getWidth (); i ++) {สำหรับ (int j = 0; j <bufferedimage.getheight (); j ++) (int) (0.3 * r + 0.59 * g + 0.11 * b); "/ok.jpg"); รหัสด้านบนจะพิมพ์ค่าพิกเซลสีเทา หากคุณเปรียบเทียบกับรหัส Python ด้านบนคุณจะพบว่าค่าพิกเซลนั้นสอดคล้องกันอย่างสมบูรณ์ วิธี colorToRGB จัดการแผนภาพสี 4 ไบต์อย่างแน่นอนหนึ่งในนั้นคือพารามิเตอร์ alpha (ดังที่ได้กล่าวไว้ก่อนหน้านี้) รูปต่อไปนี้คือภาพสีเทาของรหัสนี้:
สำหรับวิธีอื่น ๆ สามารถรับได้เหมือนกัน
สรุป
เหตุผลสำหรับบทความนี้คือการใช้ Java เพื่อใช้การดำเนินงานสีเทาหลายแห่งและใช้ OpENCV เพื่อตรวจสอบความถูกหรือผิดของการแปลง อย่างไรก็ตามพบปัญหาบางอย่างในการทดสอบจริง (มีความแตกต่างในรูปภาพที่แปลงแล้วและวิธีการสร้างภาพสีเทาตามค่าสีเทาหลังการแปลง) และความคิดและการตรวจสอบบางอย่างเกิดขึ้นในเรื่องนี้ ควรสังเกตที่นี่ว่าบทความบางอย่างบนอินเทอร์เน็ตมีการคิดเพิ่มเติมหรือน้อยลง (และหลายบทความถูกคัดลอกโดยเฉพาะอย่างยิ่งบทความในประเทศ) และสำหรับปัญหาการปฏิบัติเหล่านี้การใช้งานจริงและการตรวจสอบเป็นวิธีที่สำคัญมาก ฉันหวังว่าเนื้อหาของบทความนี้จะเป็นประโยชน์กับทุกคน หากคุณมีคำถามใด ๆ โปรดฝากข้อความเพื่อพูดคุย