🟢 Պատկերների մշակում

Ներկայումս գրեթե բոլոր սոցիալական ցանցերը հնարավորություն են տալիս խմբագրել նկարները՝ կիրառելով տարբեր տեսակի ֆիլտրեր։ Համուզված եմ, որ ձեզանից շատերդ օգտվում կամ օգտվել եք այդ հնարավորությունից։
🤖
Դասընթացի վերջին խնդիրներում մենք կգրենք ծրագրեր, որոնք կձևափոխեն մուտքային նկարը, կիրառելով նրա վրա մի քանի հայտնի ֆիլտրներ`
  1. Grayscale - նկարը դարձնում է սև և սպիտակ
  1. Sepia - նկարին տալիս է «հնության» էֆեկտ
  1. Reflection - նկարի հայելային արտապատկերում
  1. Blur - նկարին տալիս է "լղոզվածության” էֆեկտ
  1. Edge - պատկերի կոնտուրների ընդգծում
  1. Border - Եզրագծել նկարը
  1. Collage - Կոլաժների պատրաստում
 
Մինչ բուն խնդիրներին անցնելը, եկեք նախ հասկանանք, թե ինչպես է պահվում պատկերները համակարգչի հիշողության մեջ։ Մենք գիտենք, որ ցանկացած տվյալ ներկայացվում է բիթերի հաջորդականությամբ (0 և 1)։ Ամենապարզ դեպքում, կարող ենք պահել նկարի ամեն պիկսելը երկչափ զանգվածում։ Սև և սպիտակ պատկերների դեպքում ամեն պիկսելը պահելու համար մեզ հարկավոր կլինի ընդհամենը մեկ բիթ` 0 -ն կարող է ներկայացնել սև պիկսելները, իսկ 1-ը՝ սպիտակները։
 
notion image
 
Բոլորդ էլ երևի թե գիտեք, որ օգտագործելով կարմիր, կանաչ և կապույտ գույների համադրությունը հնարավոր է ստանալ «մնացած բոլոր» գույները։ Գունավոր նկարներ ստանալու համար, ամեն պիկսելին կարող ենք տրամադրել ոչ թե 1, այլ օրինակ 24 բիթ հիշողություն` առաջին 8 բիթը կօգտագործվի կապույտ գույնի արժեքը պահելու համար, հաջորդ 8 բիթը՝ կանաչ, և վերջին 8 բիթը կարմիր գույնի արժեքը պահելու համար (այսպիսի դասավորվածությունը ընդունված է անվանել BGR → Blue, Green, Red
Դիտարկենք օրինակ, հետևյալ 24 բիթ հիշողությունը։
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
1
1
1
1
1
1
1
Նկատեք, որ առաջին 16 բիթերի արժեքները 0 են, սա նշանակում է, որ պիկսելը իր մեջ չունի ոչ կապույտ, ոչ կանաչ գույներ։ Մյուս կողմից, կարմիր գույնին համապատասխան բոլոր բիթերի (վերջին 8 բիթերը) մեջ գրված է 1, սա նշանակում է, որ պիկսելը իր մեջ պարունակում է «շատ» կարմիր գույն։ Արդյունքում կստանանք լիովին կարմիր գույնի պիկսել 🟥։
Եթե բոլոր բիթերի արժեքները հավասար են 0 (պիկսելը չի պարունակում ոչ մի գույն), ապա կստանանք սև գույնը ◼️։ Եթե բոլոր բիթերի արժեքները հավասար են 1 (պիկսելը պարունակում է «բոլոր» գույները), ապա կստանանք սպիտակ գույնը։
Եթե պիկսելի կանաչ և կարմիր գույներին համապատասխան բոլոր բիթերի արժեքները հավասար են մեկ (կանաչ և կարմիր գույները միախառնված իրար), կստանանք դեղին գույնը։ 🟨
0
0
0
0
0
0
0
0
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
Եվ այսպես, փոփոխելով բիթերի արժեքները, հնարավոր է ստանալ պիկսելի տարբեր գույներ։
ℹ️
Գրականության մեջ և համացանցում գույների արժեքները ընդունված է ներկայացնել ոչ թե երկուական, այլ 16-ական համակարգով`
111111111111111111111111 → 0xffffff
000000001111111111111111 → 0x00ffff
Այս կայքում կարող եք փորձել փոփոխել կապույտ, կանաչ, կարմիր գույների արժեքները և ստանալ տարբեր գույներ։

Կարող ե՞ք հաշվել, թե քանի իրարից տարբեր գույն է հնարավոր ներկայացնել, եթե օգտագործվում է 24 բիթ հիշողություն։

24 բիթ օգտագործելու դեպքում կստանանք իրարից տարբեր գույների քանակ
 
 
ℹ️
Կարևոր է իմանալ, որ գոյություն ունեն նկարները հիշողության/ֆայլերի մեջ պահելու տարբեր ֆորմատներ (bmp, jpeg, png և այլն)։ Օրինակ, գոյություն ունեն ֆորմատներ, որոնք գույները պահում են ոչ թե BGR այլ, RGB (Red, Green, Blue) հաջորդականությամբ։ Կամ օգտագործում ոչ թե 24, այլ 8, 16 կամ 32 բիթ հիշողություն։
Նկարների խմբագրման խնդիրներում, մենք կօգտագործենք 24- բիթանոց BMP - ֆորմատը։ BMP (Bit Map) -ն նկարները ֆայլում պահելու երևի թե ամենապարզ ֆորմատներից մեկն է։ Ինչպես անունը հուշում է, այս ֆորմատով ֆայլում յուրաքանչյուր 24 բիթ իրենից ներկայացնում է նկարի մեկ պիկսել։ Պիկսելների գույները պահվում են BGR ֆորմատով։
Ստորև նկարը ցուցադրում է BMP ֆայլի պարունակություն, 16-ական համակարգով։ Մենք արդեն գիտենք, որ ffffff -ը իրենից ներկայացնում է սպիտակ գույնի պիկսել, 0000ff -ը ՝ կարմիր գույնի պիկսել։
 
BMP ֆայլի պարունակությունը՝ 16-ական ներկայացմամբ
BMP ֆայլի պարունակությունը՝ 16-ական ներկայացմամբ
Քանի որ ֆայլում պիկսելները դասավորված են ձախից աջ, վերևից ներքև հերթականությամբ, եթե նայեք նկարին քիչ հեռվից, կարող եք անգամ տեսնել պատկերը, որը պահված է ֆայլում (կարմիր գույնի ժպիտ` smile)։
Բացի բուն նկարի պիկսելներից, bmp ֆորմատը պահում է նաև լրացուցիչ տվյալներ ֆայլի վերաբերյալ։ Այս տվյալները հաճախ անվանում են մետատվյալներ (metadata)`
  1. Ֆայլի առաջին 14 բայթը պարունակում է BITMAPFILEHEADER ստրուկտուրան, որը պարունակում է ֆայլի տիպը, չափը և այլ ծառայողական ինֆորմացիա:
  1. Հաջորդ 40 բայթը պարունակում է BITMAPINFOHEADER ստրուկտուրան, որը պարունակում է տարատեսակ ինֆորմացիա պատկերի չափերի, բիթայնության վերաբերյալ և այլն։
  1. Հաջորդ բայթերը արդեն պարունակում են նկարի պիկսելները։
Եվ այսպիսով, վերևի օրինակում նկարագրված bmp ֆայլը, որը պարունակում է ժպիտի պատկերը, իրականում ունի այսպիսի տեսք։
notion image
 

Փորձարկումներ

Որպեսզի ավելի լավ պատկերացնեք, թե ինչպե՞ս է տեղի ունենում bmp ֆայլերի հետ աշխատանքը, մենք ձեզ համար պատրաստել ենք փոքրիկ ծրագիր, որը պարունակում է հետևյալ ֆայլերը`
  1. bmp.hpp - պարունակում է ստրուկտուրաներ, որոնք նկարագրում են bmp ֆայլի մետատվյալները` BITMAPFILEHEADER և BITMAPINFOHEADER, ինչպես նաև BGR ստրուկտուրան, որը նկարագրում է պիկսելը։
  1. main.cpp - ֆայլում գրված կոդը բացում է մուտքային bmp ֆայլը, գրում է ֆայլի մետատվյալները համապատասխան ստրուկտուրաների մեջ, այնուհետև տեղադրում է պատկերի պիկսելները երկչափանի զանգվածում։ Ֆայլի վերջին հատվածում գրված կոդը գրում է պատկերը նոր ֆայլում։
Ֆայլերի գրեթե բոլոր տողերը մանրամասն բացատրված են մեկնաբանություններում։
Ներբեռնեք ծրագիրը ձեր համակարգչի մեջ, և եկեք միասին կատարենք մի քանի փորձարկումներ։
  1. Նախ անհրաժեշտ է թարգմանել ծրագիրը, օգտագործելով ձեր նախընտրած թարգմանիչը։ Օրինակ ես, օգտագործում եմ g++ թարգմանիչը և ինձ մոտ թարգմանելու հրամանն ունի հետևյալ տեսքը՝
    1. g++ main.cpp -o bmp
  1. Փորձեք աշխատեցնել ծրագիրը և կտեսնեք, որ այն ուղղակի մուտքային ֆայլում գտնվող նկարը գրում է ելքային ֆայլում (out.bmp
    1. ./bmp tower.bmp out.bmp
  1. Եկեք փորձենք փոփոխել երկչափ զանգվածում պահվող նկարի պիկսելները և տեսնել թե ինչպե՞ս է փոխվում ելքային նկարը։ Օրինակ, եկեք imageManipulation ֆունկցիայում գտնվող for ցիկլի մարմնում, պիկսելի կանաչ և կապույտ գույներին վերագրել 0 արժեքը։ Նորից թարգմանեք ծրագիրը, աշխատեցրեք և կտեսնեք որ ելքային նկարի բոլոր պիկսելները պարունակում են միայն կարմիր գույնը։
    1. for (int i = 0; i < heigth; ++i) {
        for (int j = 0; j < width; ++j ) {
           image[i][j].blue = 0;
           image[i][j].green = 0;
        }
      }
  1. Փորձեք փոփոխել ֆայլի մետատվյալները և տեսեք թե ինչպե՞ս է դա ազդում ելքային ֆայլի վրա՝
    1. Ի՞նչ կպատահի, եթե փոփոխեք headerInfo ստրուկտուրայի width դաշտի արժեքը։
    2. Տպեք էկրանին headerInfo ստրուկտուրայի heigth դաշտի արժեքը։ Կտեսնեք, որ որոշ ֆայլերի համար նկարի բարձրությունը բացասական թիվ է։ Սա նշանակում է, որ ֆայլում պատկերը պահպանված է վերևից ներքև հերթականությամբ։ Ի՞նչ կպատահի ելքային նկարի հետ, եթե փոխեք heigth դաշտի արժեքի նշանը (heigth = -1 * heigth
 

Constraints

Time limit: 0.2 seconds

Memory limit: 512 MB

Output limit: 1 MB

To check your solution you need to sign in
Sign in to continue