আমাদের কথা খুঁজে নিন

   

আসুন শিখি কী করে কাজ করে JPEG [দ্বিতীয় পর্ব]

এই ব্লগের কোন লেখা আমার অনুমতি ব্যতীত কোথাও ব্যবহার না করার অনুরোধ করছি

আসুন শিখি কী করে কাজ করে JPEG (প্রথম পর্ব) গতকাল আমরা দেখেছিলাম JPEG মানে কী, কী করে এই JPEG এবং ডিজিটাল ইমেজের প্রাথমিক কিছু কথাবার্তা। আমরা এনালজি দিয়ে ব্যাখ্যাও করেছিলাম কম্প্রেসন-ডিকম্প্রেসন মানে কী। আসুন আজ আমরা জানি JPEG কীভাবে একটা র' ইমেজ বা বিটম্যাপ ইমেজ কম্প্রেসন করে JPEG ফরম্যাটে সেভ করে আমাদের বিপুল পরিমাণ মেমরি/স্টোরেজ স্পেস বাঁচিয়ে দেয়। গতকালকের আলোচনা থেকে জানি, কোন কিছুকে কম্প্রেসড অবস্থায় আসলে আমরা ব্যবহার করতে পারি না, কম্প্রেস করে শুধু জায়গা বাঁচানো সম্ভব, ব্যবহারের জন্য ডিকম্প্রেসন অত্যাবশ্যকীয়। শুরুতেই জেনে নেই- যেই সফটওয়ার/হার্ডওয়ার একটা বিটম্যাপ/র' ইমেজকে JPEG ফরম্যাটে নিয়ে এসে অল্প সংখ্যক বিট দিয়ে ইমেজটাকে প্রকাশ করে তাকে বলে JPEG এনকোডার, আর যেই সফটওয়ার/হার্ডওয়ার একটা JPEG ইমেজকে অল্প সংখ্যক বিট থেকে আবারো আগের বিটম্যাপ ইমেজের কাছাকাছি একটা ইমেজে নিয়ে যায় তাকে বলে JPEG ডিকোডার।

এই এনকোডার এবং ডিকোডার এর কনসেপ্ট আমরা ব্যবহার করব পুরো পোস্ট জুড়েই। যাইহোক, আমরা জানি, একটা র' ডিজিটাল ইমেজ মূলত একটা বিশাল ম্যাট্রিক্স ছাড়া কিছুই নয়, যার প্রতিটি উপাদানের মান ০-২৫৫ এর ভেতর(৮ বিট ইমেজের জন্য)। JPEG এনকোডার একটা র' ইমেজকে বা একটা বিশাল ম্যাট্রিক্সকে ছোট্ট করে সাজিয়ে ফেলে। কীভাবে? এটাই দেখাচ্ছি নিচে। কালকের মতোই চিন্তা করি আমাদের একটা ডিজিটাল র'/বিটম্যাপ ইমেজ আছে যা ৬৪০×৪৮০ রেজুলিউশনের, অর্থাৎ ৬৪০টি রো এবং ৪৮০টি কলাম আছে এই সুবিশাল ম্যাট্রিক্সে।

৬৪০×৪৮০ সংখ্যক পিক্সেলের প্রতিটিতেই আছে তিনটি করে রং। এখন যদি আমরা এমন করি, শুধু R এর মানগুলো নিয়ে একটা ইমেজ চিন্তা করি, আবার শুধু G এর মানগুলো নিয়ে একটা ইমেজ চিন্তা করি এবং শুধু B এর মানগুলো নিয়ে একটা ইমেজ চিন্তা করি তাহলে একটা র'/বিটম্যাপ ইমেজকে আমরা তিনটা ভাগে ভাগ করতে পারছি। প্রতিটি ভাগকে JPEG'র ভাষায় একেকটি কম্পোনেন্ট বা প্যালেট বলা হয় এবং একটা JPEG এনকোডার প্রথম ধাপে এক্সাক্টলি এই কাজটাই করে। নিচের ছবিটাতে একটা উদাহরণ দেখান হল। দ্বিতীয় ধাপে JPEG এনকোডার যা করে তা হচ্ছে প্রতিটা কম্পোনেন্ট থেকে MCU বা Minimum Coded Unit তৈরী করে।

MCU তৈরী করার জন্য প্রতিটা কম্পোনেন্ট বা প্যালেট থেকে ৮×৮ সাইজের একটা ছোট্ট ম্যাট্রিক্স কল্পনা করে নেয়। এরপর একটা R, একটা G এবং একটা B এর ৮×৮ ব্লককে পাশাপাশি বসিয়ে তৈরী করা হয় একটি MCU। এইভাবে ৮×৮ ব্লক নিতে থাকে যতক্ষণ না পুরো ইমেজটা বা বিশাল ম্যাট্রিক্সটা শেষ হয়। নিচের ছবিটা পরিস্কার করে দেবে ধারণা। তৃতীয় ধাপ থেকে শুরু গাণিতিক হিসাব-নিকাশ।

এই ধাপে একটা JPEG এনকোডার প্রতিটি ৮×৮ ব্লককে নিয়ে নির্দিষ্ট কিছু অপারেশন চালায়। আসুন আমরা ধরে নেই, কোন একটা MCUএর কোন একটা ব্লক(৮×৮ ম্যাট্রিক্স) এর পিক্সেল এর মানগুলো নিম্নরূপ। এই ম্যাট্রিক্সের প্রতিটা উপাদানের সাথে JPEG এনকোডার -১২৮ সংখ্যাটিকে যোগ করে দেবে, যার ফলাফল ম্যাট্রিক্সটা হবে নিম্নরূপ। এই ব্লকটির ক্ষেত্রে দেখতে পাচ্ছি অধিকাংশ মানই নেগেটিভ হয়ে গেছে, সবসময় এমন নাও হতে পারে। এটা নির্ভর করে মূলত পিক্সেল এর মানটা কত ছিল তার উপর।

যাই হোক, পরবর্তী ধাপে JPEG এনকোডার একটি কঠিন কাজ করবে যা বোঝার জন্য কিছুটা গণিতের জ্ঞান প্রয়োজন হবে। কঠিন কাজটির নাম 'ডোমেইন ট্রান্সফরমেশন', JPEG ইমেজ তৈরীর ক্ষেত্রে এই ডোমেইন ট্রান্সফরমেশন করতে ব্যবহার করা হয় খুবই বিখ্যাত একটি গাণিতিক সমীকরণ- DCT বা Discrete Cosine Transform। এটি ব্যাখ্যা করার আগে আসুন একটা সহজ এনালজির মাধ্যমে একটু জেনে নেই ডোমেইন ট্রান্সফরমেশন বিষয়টা কী? মনে করি আমরা অনেক বছর আগে বাস করছি, অন্তত একশ-দেড়শ বছর আগে, যখন এক পয়সার মূল্য অনেক ছিল। অর্থাৎ মানুষ যাবতীয় কেনাকাটা করত পয়সাতে, টাকা একটা অনেক বড় অঙ্ক ছিল। আপনি যদি সেই সময়ে এখনকার মতো ৩৫,০০০ টাকা রোজগার করেন মাসে, তাহলে আপনি টাকা টা কোন এককে গুনবেন? পয়সাতে? কত পয়সা হবে ৩৫,০০০ টাকায়? ৩৫,০০০×১০০=৩৫,০০,০০০ পয়সা! নিশ্চয়ই এটা আপনার বেতনের টাকা গণনা করার জন্য সঠিক একক হবে না।

আপনার জন্যে তখন একক পরিবর্তন করতে হবে টাকায়, যেন আপনাকে '৩৫ লক্ষ পয়সা বেতন পাই' না পেয়ে '৩৫ হাজার টাকা বেতন পাই' সহজে প্রকাশ করতে পারেন, যদিও আপনার দৈনন্দিন বাজার সদাই আপনি পয়সাতেই করে চলেছেন। আপনিও কিন্তু একটা ট্রান্সফরমেশন করলেন, 'পয়সা' ডোমেইন থেকে 'টাকা' ডোমেইনে চলে গেলেন, শুধুমাত্র আপনার হিসাব করার সুবিধার্থে। ঠিক একইভাবে, তথ্য-প্রযুক্তির গবেষণার ক্ষেত্রগুলোতে আমরা একটা ডোমেইন থেকে আরেকটা ডোমেইনে চলে যাই শুধুমাত্র যে কাজটা করছি তা সহজভাবে করার সুবিধার্থে। সবচেয়ে কমন একটা ট্রান্সফরমেশন হচ্ছে টাইম ডোমেইন থেকে ফ্রিকোয়েন্সি ডোমেইনে কনভার্শন, যা করা হয় বিখ্যাত ফোরিয়ার ট্রান্সফর্ম সমীকরণ ব্যবহার করে। অবশ্যই, আমাদের আবার পূর্বের ডোমেইনে ফিরে আসার ব্যবস্থা রাখতে হবে, যেমন টাকায় গুনলেও, আপনি বাজার করার জন্য টাকার হিসাবে না নিয়ে পয়সার হিসাবেই আবার ফিরে আসেন।

যাইহোক, বলছিলাম, JPEG এনকোডার DCT বা Discrete Cosine Transform ব্যবহার করে আমাদের আলোচ্য ম্যাট্রিক্সটাকে yx(y=row, x=column) ডোমেইন থেকে vu(v=row, u=column) ডোমেইনে নিয়ে যাবে। এটা করলে লাভ হচ্ছে আমাদের অনেকগুলো মান ছোট হয়ে যাবে। যেহেতু আমাদের টার্গেট হচ্ছে ইমেজ কম্প্রেসন করা, সে জন্য পিক্সেল এর মানগুলো যতটা সম্ভব ছোট করে ফেলাটাই আমাদের মূল লক্ষ্য। নিচের ছবিতে দেখান হল Discrete Cosine Transform এর সমীকরণটা। এখানে একটা yx ম্যাট্রিক্সকে ইনপুট দিলে আমরা একটা vu ম্যাট্রিক্স পাই, নিচে vu ম্যাট্রিক্সটা দেখান হল, লক্ষ্যণীয় যে অনেকগুলো পিক্সেল এর মান যা ছিল তার চেয়ে অনেক ছোট হয়ে এসেছে, এটাই ডোমেইন ট্রান্সফরমেশনের মূল শক্তি।

কী করে কাজ করে এই DCT সেটা আলোচনায় না আনি, কারও জানার আগ্রহ থাকলে সেটা পরবর্তীতে আলোচনা করা যাবে। এবারে JPEG এনকোডার যেই ম্যাট্রিক্সটা পেল সেটাকে কোয়ান্টাইজ করবে। নন-টেকনিক্যাল ভাষায় কোয়ান্টাইজ বলতে আমরা বুঝব ছোট ছোট করে ভাগ করা। Joint Photographic Experts Group নির্ধারণ করে দিয়েছে কোয়ান্টাইজ করার জন্য একটা স্ট্যান্ডার্ড ম্যাট্রিক্স, তবে আপনি চাইলে এই ম্যাট্রিক্সের উপাদানগুলোর মান নিজের ইচ্ছেমত বাড়াতে কমাতে পারবেন, এই স্বাধীনতা JPEG ব্যবহারকারীদের দেয়। নিচের চিত্রে দেখান হল স্ট্যান্ডার্ড কোয়ান্টাইজেশন ম্যাট্রিক্সটা।

এই ম্যাট্রিক্সের প্রতিটি উপাদান দিয়ে আমাদের ডোমেইন ট্রান্সফর্ম করার ফলে প্রাপ্ত ম্যাট্রিক্সের প্রতিটি উপাদানকে আমরা ভাগ করব, অর্থাৎ -৪১৫ কে ভাগ করব ১৬ দিয়ে, -৩০ কে ভাগ করব ১১ দিয়ে.....এবং প্রাপ্ত ফলাফলগুলোকে রাউন্ড করে নিব নিচের মত করে। রাউন্ড করা মানে হচ্ছে দশমিক এর পর ৫০ এর চেয়ে ছোট হলে মূল ফলাফলের চেয়ে ছোট সর্বোচ্চ পূর্ণসংখ্যা নেয়া আর দশমিক এর পর ৫০ এর চেয়ে বড় হলে মূল ফলাফলের চেয়ে বড় সর্বনিম্ন পূর্ণসংখ্যা নেয়া। উদাহরণস্বরূপ ৪১৫ কে ১৬ দিয়ে ভাগ করলে পাই ২৫.৯৩, যেহেতু দশমিক এর পর মানটা ৫০ এর চেয়ে বড়, তাই আমরা ২৫.৯৩ এর চেয়ে বড় সর্বনিম্ন পূর্ণসংখ্যা ২৬ নিয়েছি। কী দেখলাম? দেখা গেল বেশিরভাগ পিক্সেল এর মানই শূণ্য চলে এসেছে, আমাদের লক্ষ্যই ছিল পিক্সেল এর মানগুলোকে যতটা সম্ভব ছোট করা। বিচিত্র হলেও সত্য যে, কম্পিউটারের ক্ষেত্রে ০ এর চেয়ে ছোট কোন মান নেই, -১ গাণিতিকভাবে ০ এর চেয়ে ছোট হলেও, একে প্রকাশ করতে অনেকগুলো বিট লাগে, অথচ শুণ্যকে প্রকাশ করতে কেবল একটা বিট লাগে।

যাইহোক, একটু লক্ষ্য করলেই দেখব আমাদের কোয়ান্টাইজেশন ম্যাট্রিক্সটার মানগুলো এমন ছিল যে আপার ট্রায়াঙ্গুলার অংশে ছিল অপেক্ষাকৃত ছোট মান, এবং লোয়ার ট্রায়াংগুলার অংশে ছিল অপেক্ষাকৃত বড় মান। যেহেতু ডোমেইন ট্রান্সফর্ম করার ফলে প্রাপ্ত ম্যাট্রিক্সের লোয়ার ট্রায়াংগুলার অংশে এমনিই ছোট ছোট মান এসেছিল, এখন এগুলোকে বড় সংখ্যা দিয়ে ভাগ করলে তো শূণ্যই আসবে। লক্ষ্য করুন, আমরা যখন এই ইমেজটাকে আবার ডিকোড বা ডিকম্প্রেস করব, নিশ্চয়ই এই পর্যায়ে প্রাপ্ত -২৬ কে আবার ১৬ দিয়ে গুণ দিব ভাগের ইনভার্স অপারেশন হিসাবে? কিন্তু তাতে কি কখনো আমরা এক্সাক্টলি -৪১৫ ফিরে পাব? কখনোই না। JPEG সাধারণ অর্থে এমন একটা কম্প্রেসন মেকানিজম যা আপনার ইমেজের সঠিক মানগুলো কখনোই ফিরিয়ে দিবে না, অর্থাৎ ডাটা loss হবে, ইমেজের কোয়ালিটি তাই যা ছিল তা আর থাকবে না। এমনকি, যতবার আপনি একটা ইমেজকে JPEGর মেকানিজমে কম্প্রেস আর ডিকম্প্রেস করবেন, প্রতিটিবার আপনি হারাবেন একটু করে কোয়ালিটি।

এখন, কী হতো যদি আমরা কোয়ান্টাইজেশন ম্যাট্রিক্সটার উপাদানগুলোর মান সব ১ নিতাম? তাহলে ভাগ করার পরও যা ছিল তাই থাকত। তাহলে আবার ডিকোড করার সময় গুণ করলেও কোন ক্ষতি আসলে হতো না পিক্সেল এর মানগুলোর। যা আগে ছিল তাই থাকত। আবার যদি আমরা কোয়ান্টাইজেশন ম্যাট্রিক্সটার উপাদানগুলোর মান সব ২৫৫ নেই, তাহলে সবচেয়ে বেশি লস হবে ডাটার, প্রায় সবগুলো মানই শুণ্য চলে আসবে। তাই না? আপনি হয়তো ফটোশপ বা অন্য কোন ডিজিটাল ফটো এডিটিং সফটওয়ার ব্যবহার করে কোন ইমেজকে JPEG ফরম্যাটে সেভ করার সময় দেখেছেন 'কম্প্রেশন রেশিও' নামক একটা অপশন।

এই খানে আপনি মান যত বাড়াবেন মূলত আমাদের কোয়ান্টাইজেশন ম্যাট্রিক্সটার মান তত বাড়বে, ইমেজ তত বেশি কম্প্রেসড হবে, ডাটা তত বেশি লস হবে। আবার এখানে আপনি মান যত কমাবেন, কোয়ান্টাইজেশন ম্যাট্রিক্সটার মান তত কমবে, ইমেজ তত কম কম্প্রেসড হবে, ডাটা লস হওয়ার পরিমাণ তত কমবে। যাইহোক, কম্পিউটার তো ০ অথবা ১ ছাড়া কোন কিছু সংরক্ষণ করতে পারে না, আমরা আগের পোস্টে দেখেছিলাম কী করে একটা র' ইমেজ কে কম্পিউটার জায়গা করে দেয়া মেমরি/স্টোরেজ ডিভাইসে। এখন আমরা যে ম্যাট্রিক্সটা সর্বশেষ পেয়েছি, তাকেও তো বাইনারি তে নিতে হবে, না হলে কী করে কম্পিউটার সংরক্ষণ করবে একে? আমাদের সর্বশেষ প্রাপ্ত ম্যাট্রিক্সটাতে কম্পিউটার একটা জিগজ্যাগ স্ক্যান চালাবে নিচের চিত্রের মতো করে এবং পিক্সেল ভ্যালুগুলো রিড করবে। যেই মানগুলো আমরা এখন পেলাম এই ধরণের কিছু মান নিশ্চয়ই আমরা প্রতিটা MCU এর প্রতিটা ব্লকের জন্য পাব? এই মানগুলোর প্রথম সংখ্যাটাকে JPEGর ভাষায় আমরা বলি ডিসি কো-এফিশিয়েন্ট, যা নির্ধারণ করে দেয় প্রতিটা ব্লকের রং কী হবে, বাকিগুলোকে আমরা বলি এসি-কোএফিশিয়েন্ট।

যেখান থেকে বাকি সবগুলো মান শুণ্য হয়ে গেছে, সেগুলোকে আমরা EOB(End of Block) হিসাবে চিহ্নিত করি। এখন এই মানগুলোর উপর ভেরিয়েবল লেঙ্গথ কোডিং চালানো হয়। অর্থাৎ, কোন একটি সংখ্যা বেশি বার থাকলে তাকে সবচেয় কম সংখ্যক বিট দিয়ে প্রকাশ করা হয় এবং কোন সংখ্যা কম বার থাকলে তাকে সবচেয়ে বেশি সংখ্যক বিট দিয়ে প্রকাশ করা হয়। এই ভেরিয়েবল লেঙ্গথ কোডিং এর জন্য 'হাফম্যান এলগরিদম' বা 'এরিথমেটিক কোডিং' নামক কিছু অপটিমাল এলগরিদম ব্যবহার করা হয়। এই ভেরিয়েবল লেঙ্গথ কোডিং একটা বিশাল অংশ, পোস্ট যথেষ্ট বড় হওয়াতে আমি এড়িয়ে যাচ্ছি এটাকে, আপনাদের আগ্রহ থাকলে আরেকটা পোস্ট দেয়া যেতে পারে শুধু ভেরিয়েবল লেঙ্গথ কোডিং নিয়েই।

যাইহোক, সবশেষে আমরা একটা ব্লক(৮×৮) এর জন্য এমন কিছু বিট কম্বিনেশন পাই- 1010110 0100 001 0100 0101 100001 0110 100011 001 100011 001 001 100101 11100110 110110 0110 11110100 000 1010. কারও যদি গুণে দেখার মতো ধৈর্য এখনো থাকে তবে পরীক্ষা করে দেখুন এখানে মাত্র ৯২টি বিট আছে! অথচ এই ব্লকটি যখন বিটম্যাপ/র' ইমেজের ছিল তখন এখানে ছিল ৮×৮×২৪=৫১২টি বিট। তাহলে আমাদের অর্জিত কম্প্রেসন রেশিও হচ্ছে ৫১২÷৯২। একটা ব্লক থেকেই আমরা ৪২০টি বিট কমিয়ে দিয়েছি JPEG কম্প্রেসন টেকনিক ব্যবহার করে, বলুন, কেন JPEG এতটা পপুলার হবে না? যদি সবগুলো ব্লককে এইভাবে হিসাব করি, আমরা দেখতে পাব JPEG কিছুটা লস হলেও এমন বিস্ময়কর কম্প্রেসন রেশিও দেয় যা তদানীন্তন অন্য কোন কম্প্রেসন এলগরিদম দিতে পারেনি। আসুন, শেষ কথায় আসি। কম্প্রেসন তো হলো, এবার ডিকম্প্রেস না করলে কী করে দেখা যাবে এই ইমেজটি? নিশ্চয়ই এই ৯২টি বিট আমাকে সেই একই জিনিস দেখাবে না, ৫১২টি বিট যা দেখাত।

তাহলে আবার একে ৫১২টি বিটে ফিরিয়ে নিয়ে যেতে হবে, এই কাজটি আমরা করতে পারি JPEG ডিকোডার এর সাহায্যে। যেই ধাপগুলো পেরিয়ে এসেছি, শুধু সেগুলোকে আবার উল্টোভাবে করে যেতে হবে এর, একটা জায়াগায় সামান্য ব্যতিক্রম বাদে। আমরা Discrete Cosine Transform ব্যবহার করে yx থেকে vu ডোমেইনে চলে এসেছিলাম, এবার yx এ ফেরত যেতে হলে Inverse Discrete Cosine Transform ব্যবহার করতে হবে, যেই সমীকরণটি নিচের চিত্রে দেখান আছে। সবাইকে অসংখ্য ধন্যবাদ। এই বিশাল লেখার কিছুমাত্রও আপনাদের ভালো লেগে থাকলে এবং কাজে আসলে আমার কষ্ট সার্থক হবে।


সোর্স: http://www.somewhereinblog.net     দেখা হয়েছে বার

এর পর.....

অনলাইনে ছড়িয়ে ছিটিয়ে থাকা কথা গুলোকেই সহজে জানবার সুবিধার জন্য একত্রিত করে আমাদের কথা । এখানে সংগৃহিত কথা গুলোর সত্ব (copyright) সম্পূর্ণভাবে সোর্স সাইটের লেখকের এবং আমাদের কথাতে প্রতিটা কথাতেই সোর্স সাইটের রেফারেন্স লিংক উধৃত আছে ।