Ներկայումս գրեթե բոլոր սոցիալական ցանցերը հնարավորություն են տալիս խմբագրել նկարները՝ կիրառելով տարբեր տեսակի ֆիլտրեր։ Համուզված եմ, որ ձեզանից շատերդ օգտվում կամ օգտվել եք այդ հնարավորությունից։
Դասընթացի վերջին խնդիրներում մենք կգրենք ծրագրեր, որոնք կձևափոխեն մուտքային նկարը, կիրառելով նրա վրա մի քանի հայտնի ֆիլտրներ`
Grayscale
- նկարը դարձնում է սև և սպիտակ
Sepia
- նկարին տալիս է «հնության» էֆեկտ
Reflection
- նկարի հայելային արտապատկերում
Blur
- նկարին տալիս է "լղոզվածության” էֆեկտ
Edge
- պատկերի կոնտուրների ընդգծում
Border
- Եզրագծել նկարը
Collage
- Կոլաժների պատրաստում
Մինչ բուն խնդիրներին անցնելը, եկեք նախ հասկանանք, թե ինչպես է պահվում պատկերները համակարգչի հիշողության մեջ։ Մենք գիտենք, որ ցանկացած տվյալ ներկայացվում է բիթերի հաջորդականությամբ (0 և 1)։ Ամենապարզ դեպքում, կարող ենք պահել նկարի ամեն պիկսելը երկչափ զանգվածում։ Սև և սպիտակ պատկերների դեպքում ամեն պիկսելը պահելու համար մեզ հարկավոր կլինի ընդհամենը մեկ բիթ`
0
-ն կարող է ներկայացնել սև պիկսելները, իսկ 1
-ը՝ սպիտակները։ 
Բոլորդ էլ երևի թե գիտեք, որ օգտագործելով կարմիր, կանաչ և կապույտ գույների համադրությունը հնարավոր է ստանալ «մնացած բոլոր» գույները։ Գունավոր նկարներ ստանալու համար, ամեն պիկսելին կարող ենք տրամադրել ոչ թե
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
-ը ՝ կարմիր գույնի պիկսել։ 
Քանի որ ֆայլում պիկսելները դասավորված են ձախից աջ, վերևից ներքև հերթականությամբ, եթե նայեք նկարին քիչ հեռվից, կարող եք անգամ տեսնել պատկերը, որը պահված է ֆայլում (կարմիր գույնի ժպիտ` smile)։
Բացի բուն նկարի պիկսելներից,
bmp
ֆորմատը պահում է նաև լրացուցիչ տվյալներ ֆայլի վերաբերյալ։ Այս տվյալները հաճախ անվանում են մետատվյալներ (metadata)`- Ֆայլի առաջին
14
բայթը պարունակում էBITMAPFILEHEADER
ստրուկտուրան, որը պարունակում է ֆայլի տիպը, չափը և այլ ծառայողական ինֆորմացիա:
- Հաջորդ 40 բայթը պարունակում է
BITMAPINFOHEADER
ստրուկտուրան, որը պարունակում է տարատեսակ ինֆորմացիա պատկերի չափերի, բիթայնության վերաբերյալ և այլն։
- Հաջորդ բայթերը արդեն պարունակում են նկարի պիկսելները։
Եվ այսպիսով, վերևի օրինակում նկարագրված
bmp
ֆայլը, որը պարունակում է ժպիտի պատկերը, իրականում ունի այսպիսի տեսք։
Փորձարկումներ
Որպեսզի ավելի լավ պատկերացնեք, թե ինչպե՞ս է տեղի ունենում
bmp
ֆայլերի հետ աշխատանքը, մենք ձեզ համար պատրաստել ենք փոքրիկ ծրագիր, որը պարունակում է հետևյալ ֆայլերը`-
bmp.hpp
- պարունակում է ստրուկտուրաներ, որոնք նկարագրում ենbmp
ֆայլի մետատվյալները`BITMAPFILEHEADER
ևBITMAPINFOHEADER
,
ինչպես նաևBGR
ստրուկտուրան, որը նկարագրում է պիկսելը։
main.cpp
- ֆայլում գրված կոդը բացում է մուտքային bmp ֆայլը, գրում է ֆայլի մետատվյալները համապատասխան ստրուկտուրաների մեջ, այնուհետև տեղադրում է պատկերի պիկսելները երկչափանի զանգվածում։ Ֆայլի վերջին հատվածում գրված կոդը գրում է պատկերը նոր ֆայլում։
Ֆայլերի գրեթե բոլոր տողերը մանրամասն բացատրված են մեկնաբանություններում։
Ներբեռնեք ծրագիրը ձեր համակարգչի մեջ, և եկեք միասին կատարենք մի քանի փորձարկումներ։
- Նախ անհրաժեշտ է թարգմանել ծրագիրը, օգտագործելով ձեր նախընտրած թարգմանիչը։ Օրինակ ես, օգտագործում եմ g++ թարգմանիչը և ինձ մոտ թարգմանելու հրամանն ունի հետևյալ տեսքը՝
g++ main.cpp -o bmp
- Փորձեք աշխատեցնել ծրագիրը և կտեսնեք, որ այն ուղղակի մուտքային ֆայլում գտնվող նկարը գրում է ելքային ֆայլում (
out.bmp
)։
./bmp tower.bmp out.bmp
- Եկեք փորձենք փոփոխել երկչափ զանգվածում պահվող նկարի պիկսելները և տեսնել թե ինչպե՞ս է փոխվում ելքային նկարը։ Օրինակ, եկեք
imageManipulation
ֆունկցիայում գտնվողfor
ցիկլի մարմնում, պիկսելի կանաչ և կապույտ գույներին վերագրել0
արժեքը։ Նորից թարգմանեք ծրագիրը, աշխատեցրեք և կտեսնեք որ ելքային նկարի բոլոր պիկսելները պարունակում են միայն կարմիր գույնը։
for (int i = 0; i < heigth; ++i) { for (int j = 0; j < width; ++j ) { image[i][j].blue = 0; image[i][j].green = 0; } }
- Փորձեք փոփոխել ֆայլի մետատվյալները և տեսեք թե ինչպե՞ս է դա ազդում ելքային ֆայլի վրա՝
- Ի՞նչ կպատահի, եթե փոփոխեք
headerInfo
ստրուկտուրայի width դաշտի արժեքը։ - Տպեք էկրանին
headerInfo
ստրուկտուրայիheigth
դաշտի արժեքը։ Կտեսնեք, որ որոշ ֆայլերի համար նկարի բարձրությունը բացասական թիվ է։ Սա նշանակում է, որ ֆայլում պատկերը պահպանված է վերևից ներքև հերթականությամբ։ Ի՞նչ կպատահի ելքային նկարի հետ, եթե փոխեքheigth
դաշտի արժեքի նշանը (heigth = -1 * heigth
)։