Programmēšana

Attēlu apstrāde ar Java 2D

Attēlu apstrāde ir māksla un zinātne par manipulācijām ar digitālajiem attēliem. Tā ar vienu kāju stingri stāv matemātikā, bet otra - estētikā, un ir kritiska grafisko datorsistēmu sastāvdaļa. Ja jūs kādreiz esat apnikuši, veidojot savus attēlus tīmekļa lapām, jūs, bez šaubām, novērtēsiet Photoshop attēlu manipulācijas iespēju nozīmi skenēšanas attīrīšanā un attēlu attīrīšanā, kas nav optimālāka.

Ja jūs veicāt kādu attēlu apstrādes darbu JDK 1.0 vai 1.1 versijā, jūs, iespējams, atceraties, ka tas bija nedaudz mīksts. Attēlu datu ražotāju un patērētāju vecais modelis ir apgrūtinošs attēlu apstrādei. Pirms JDK 1.2 tika iesaistīta attēlu apstrāde MemoryImageSources, PixelGrabbers, un citas tādas arkānas. Tomēr Java 2D nodrošina tīrāku, vieglāk lietojamu modeli.

Šajā mēnesī mēs izskatīsim vairāku svarīgu attēlu apstrādes darbību algoritmus (ops) un parādīs, kā tos var ieviest, izmantojot Java 2D. Mēs arī parādīsim, kā šie opi tiek izmantoti, lai ietekmētu attēla izskatu.

Tā kā attēlu apstrāde ir patiešām noderīga atsevišķa Java 2D lietojumprogramma, mēs esam izveidojuši šī mēneša piemēru ImageDicer, lai tas būtu pēc iespējas vairāk izmantojams jūsu pašu lietojumprogrammām. Šis vienīgais piemērs parāda visas attēlu apstrādes metodes, kuras aplūkosim šī mēneša slejā.

Ņemiet vērā, ka neilgi pirms šī raksta publicēšanas Sun izlaida Java 1.2 Beta 4 izstrādes komplektu. Beta 4, šķiet, nodrošina labāku veiktspēju mūsu attēlu apstrādes piemēru paraugiem, taču tas arī pievieno dažas jaunas kļūdas, kas saistītas ar robežu pārbaudi ConvolveOps. Šīs problēmas ietekmē malu noteikšanas un asināšanas piemērus, kurus mēs izmantojam mūsu diskusijā.

Mēs domājam, ka šie piemēri ir vērtīgi, tāpēc, nevis tos pilnībā izlaist, mēs kompromitējām: lai nodrošinātu tā darbību, parauga kods atspoguļo Beta 4 izmaiņas, taču mēs esam saglabājuši skaitļus no 1.2 Beta 3 izpildes, lai jūs varētu redzēt operācijas darbojas pareizi.

Cerams, ka Sun novērsīs šīs kļūdas pirms Java 1.2 izlaišanas.

Attēlu apstrāde nav raķešu zinātne

Attēlu apstrādei nav jābūt grūtai. Patiesībā pamatjēdzieni patiešām ir diezgan vienkārši. Galu galā attēls ir tikai krāsainu pikseļu taisnstūris. Attēla apstrāde ir vienkārši katra pikseļa jaunas krāsas aprēķināšana. Katra pikseļa jaunā krāsa var būt balstīta uz esošo pikseļu krāsu, apkārtējo pikseļu krāsu, citiem parametriem vai šo elementu kombināciju.

2D API ievieš vienkāršu attēlu apstrādes modeli, lai palīdzētu izstrādātājiem manipulēt ar šiem attēlu pikseļiem. Šis modelis ir balstīts uz java.awt.image.BufferedImage klases un attēlu apstrādes darbības, piemēram, konvolūcija un sliekšņa noteikšana ir pārstāvēti ar java.awt.image.BufferedImageOp interfeiss.

Šo opu ieviešana ir samērā vienkārša. Pieņemsim, ka, piemēram, avota attēls jums jau ir kā Buferēts attēls sauca avots. Veicot operāciju, kas parādīta attēlā iepriekš, būtu nepieciešamas tikai dažas koda rindiņas:

001 īss [] slieksnis = jauns īss [256]; 002 par (int i = 0; i <256; i ++) 003 slieksni [i] = (i <128)? (īss) 0: (īss) 255; 004 BufferedImageOp thresholdOp = 005 jauns LookupOp (jauns ShortLookupTable (0, slieksnis), null); 006 BufferedImage galamērķis = thresholdOp.filter (avots, null); 

Tas tiešām ir viss. Tagad apskatīsim soļus sīkāk:

  1. Uzreiz izvēlieties attēlu darbību (004. un 005. rinda). Šeit mēs izmantojām a Meklēt, kas ir viena no attēlu operācijām, kas iekļautas Java 2D ieviešanā. Tāpat kā jebkura cita attēla darbība, tā īsteno BufferedImageOp interfeiss. Par šo operāciju mēs runāsim vēlāk.

  2. Zvaniet uz operāciju filtrs () metode ar avota attēlu (006. rinda). Avots tiek apstrādāts un galamērķa attēls tiek atgriezts.

Ja esat jau izveidojis Buferēts attēls kurā būs galamērķa attēls, varat to nodot kā otro parametru filtrs (). Ja jūs izturēsit nulle, kā mēs to darījām iepriekš minētajā piemērā, jauns galamērķis Buferēts attēls ir izveidots.

2D API ietver nedaudz šo iebūvēto attēlu darbību. Šajā slejā mēs apspriedīsim trīs: konvolūcija,uzmeklēšanas tabulas, un sliekšņa noteikšana. Lūdzu, skatiet Java 2D dokumentāciju, lai iegūtu informāciju par pārējām 2D API (Resursi) pieejamajām darbībām.

Konversija

A konvolūcija darbība ļauj apvienot avota pikseļa un tā kaimiņu krāsas, lai noteiktu galamērķa pikseļa krāsu. Šī kombinācija ir norādīta, izmantojot a kodols, lineārs operators, kas nosaka katras avota pikseļu krāsas proporciju, kas izmantota galamērķa pikseļa krāsas aprēķināšanai.

Iedomājieties kodolu kā veidni, kas ir pārklāta ar attēlu, lai veiktu konvolūciju vienā pikselī vienlaikus. Katram pikseļam liekoties, veidne tiek pārvietota uz nākamo pikseļu avota attēlā un konvolūcijas process tiek atkārtots. Attēla avota kopija tiek izmantota konvekcijas ievades vērtībām, un visas izvades vērtības tiek saglabātas attēla galamērķa kopijā. Kad konvolūcijas darbība ir pabeigta, mērķa attēls tiek atgriezts.

Kodola centru var uzskatīt par savērpta avota pikseļa pārklājumu. Piemēram, konvolūcijas darbība, kurā tiek izmantots šāds kodols, neietekmē attēlu: katram mērķa pikseļam ir tāda pati krāsa kā atbilstošajam avota pikseļam.

 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 

Galvenais noteikums kodolu izveidošanai ir tāds, ka visiem elementiem ir jāsasniedz 1, ja vēlaties saglabāt attēla spilgtumu.

2D API konvolūciju attēlo a java.awt.image.ConvolveOp. Jūs varat izveidot a ConvolveOp izmantojot kodolu, kuru attēlo java.awt.image.Kernel. Šis kods konstruē a ConvolveOp izmantojot iepriekš uzrādīto kodolu.

001 pludiņš [] identitāteKernel = {002 0,0f, 0,0f, 0,0f, 003 0,0f, 1,0f, 0,0f, 004 0,0f, 0,0f, 0,0f 005}; 006 BufferedImageOp identitāte = 007 jauns ConvolveOp (jauns kodols (3, 3, identitātes kodols)); 

Konvolūcijas darbība ir noderīga, veicot vairākas kopīgas darbības ar attēliem, kuras mēs detalizēti aprakstīsim vienā mirklī. Dažādi kodoli rada radikāli atšķirīgus rezultātus.

Tagad mēs esam gatavi ilustrēt dažus attēlu apstrādes kodolus un to efektus. Mūsu nemodificētais attēls ir Lady Agnew no Lochnaw, gleznojis Džons Singers Sargents 1892. un 1893. gadā.

Šis kods izveido a ConvolveOp kas apvieno vienādu daudzumu katra avota pikseļa un tā kaimiņu. Šī tehnika rada izplūdušu efektu.

001 pludiņš devītais = 1,0f / 9,0f; 002 pludiņš [] blurKernel = {003 devītais, devītais, devītais, 004 devītais, devītais, devītais, 005 devītais, devītais, devītais 006}; 007 BufferedImageOp izplūšana = new ConvolveOp (jauns kodols (3, 3, blurKernel)); 

Cits izplatīts konvekcijas kodols uzsver attēla malas. Šo darbību parasti sauc malu noteikšana. Atšķirībā no citiem šeit uzrādītajiem kodoliem, šī kodola koeficienti nepārsniedz 1.

001 pludiņš [] edgeKernel = {002 0,0f, -1,0f, 0,0f, 003 -1,0f, 4,0f, -1,0f, 004 0,0f, -1,0f, 0,0f 005}; 006 BufferedImageOp mala = new ConvolveOp (jauns kodols (3, 3, edgeKernel)); 

Jūs varat redzēt, ko šis kodols dara, apskatot koeficientus kodolā (līnijas 002-004). Uz brīdi padomājiet par to, kā malu noteikšanas kodolu izmanto, lai darbotos apgabalā, kas ir pilnīgi vienas krāsas. Katram pikseļam beigsies krāsa (melna), jo apkārtējo pikseļu krāsa atceļ avota pikseļa krāsu. Spilgti pikseļi, kurus ieskauj tumši pikseļi, paliks spilgti.

Ievērojiet, cik apstrādātais attēls ir tumšāks, salīdzinot ar oriģinālu. Tas notiek tāpēc, ka malu noteikšanas kodola elementi nesasniedz 1.

Vienkārša malu noteikšanas variācija ir asināšana kodols. Šajā gadījumā avota attēls tiek pievienots malu noteikšanas kodolam šādi:

 0.0 -1.0 0.0 0.0 0.0 0.0 0.0 -1.0 0.0 -1.0 4.0 -1.0 + 0.0 1.0 0.0 = -1.0 5.0 -1.0 0.0 -1.0 0.0 0.0 0.0 0.0 0.0 -1.0 0.0 

Asināšanas kodols faktiski ir tikai viens iespējamais kodols, kas asina attēlus.

3 x 3 kodola izvēle ir nedaudz patvaļīga. Jūs varat definēt jebkura izmēra kodolus, un, domājams, tiem pat nav jābūt kvadrātveida. Tomēr JDK 1.2 Beta 3 un 4 versijā kodols, kas nav kvadrāts, izraisīja lietojumprogrammas avāriju, un 5 x 5 kodols sakodrēja attēla datus visdīvainākajā veidā. Ja jums nav pārliecinoša iemesla atkāpties no 3 x 3 kodoliem, mēs to neiesakām.

Jums var būt arī jautājums, kas notiek attēla malā. Kā jūs zināt, pārveidošanas operācijā tiek ņemti vērā avota pikseļa kaimiņi, bet avota pikseļiem attēla malās nav kaimiņu vienā pusē. The ConvolveOp klasē ietilpst konstantes, kas norāda, kādai uzvedībai jābūt malās. The EDGE_ZERO_FILL konstante norāda, ka galamērķa attēla malas ir iestatītas uz 0. The EDGE_NO_OP konstante norāda, ka avota pikseļi gar attēla malu tiek kopēti uz galamērķi bez izmaiņām. Ja, veidojot a, nenorādat malu uzvedību ConvolveOp, EDGE_ZERO_FILL tiek izmantots.

Šis piemērs parāda, kā jūs varētu izveidot asināšanas operatoru, kas izmanto EDGE_NO_OP likums (NO_OP tiek nodots kā a ConvolveOp parametrs 008. rindā):

001 pludiņš [] sharpKernel = {002 0.0f, -1.0f, 0.0f, 003 -1.0f, 5.0f, -1.0f, 004 0.0f, -1.0f, 0.0f 005}; 006 BufferedImageOp sharpen = jauns ConvolveOp (007 jauns kodols (3, 3, sharpKernel), 008 ConvolveOp.EDGE_NO_OP, null); 

Uzmeklēšanas tabulas

Vēl viena daudzpusīga attēla darbība ietver a uzmeklēšanas tabula. Šai darbībai avota pikseļu krāsas tiek pārveidotas galamērķa pikseļu krāsās, izmantojot tabulu. Atcerieties, ka krāsa sastāv no sarkaniem, zaļiem un ziliem komponentiem. Katra komponenta vērtība ir no 0 līdz 255. Trīs tabulas ar 256 ierakstiem ir pietiekamas, lai jebkuru avota krāsu pārveidotu par galamērķa krāsu.

The java.awt.image.LookupOp un java.awt.image.LookupTable klases iekapsulē šo darbību. Katram krāsu komponentam varat noteikt atsevišķas tabulas vai visiem trim izmantot vienu tabulu. Apskatīsim vienkāršu piemēru, kas apgriež katra komponenta krāsas. Viss, kas mums jādara, ir izveidot masīvu, kas apzīmē tabulu (rindas 001-003). Tad mēs izveidojam a Uzmeklēšanas tabula no masīva un a Meklēt no Uzmeklēšanas tabula (004.-005. rinda).

001 īss [] invert = jauns īss [256]; 002 par (int i = 0; i <256; i ++) 003 invertēt [i] = (īss) (255 - i); 004 BufferedImageOp invertOp = new LookupOp (005 jauns ShortLookupTable (0, invert), null); 

Uzmeklēšanas tabula ir divas apakšklases, ByteLookupTable un ShortLookupTable, kas iekapsulējas baits un īss masīvi. Ja izveidojat a Uzmeklēšanas tabula kurā nav ieraksta nevienai ievades vērtībai, tiks izmests izņēmums.

Šī darbība rada efektu, kas parastajā filmā izskatās kā krāsu negatīvs. Ņemiet vērā arī to, ka divreiz lietojot šo darbību, tiks atjaunots sākotnējais attēls; jūs būtībā ņemat negatīvo no negatīvā.

Ko darīt, ja vēlaties ietekmēt tikai vienu no krāsu komponentiem? Viegli. Jūs konstruējat a Uzmeklēšanas tabula ar atsevišķām tabulām katram sarkanajam, zaļajam un zilajam komponentam. Šis piemērs parāda, kā izveidot Meklēt kas apgriež tikai krāsas zilo komponentu. Tāpat kā ar iepriekšējo inversijas operatoru, divreiz lietojot šo operatoru, tiek atjaunots sākotnējais attēls.

001 īss [] invert = jauns īss [256]; 002 īss [] taisns = jauns īss [256]; 003 par (int i = 0; i <256; i ++) {004 invertēt [i] = (īss) (255 - i); 005 taisns [i] = (īss) i; 006} 007 īss [] [] blueInvert = jauns īss [] [] {taisns, taisns, apgriezts}; 008 BufferedImageOp blueInvertOp = 009 jauns LookupOp (jauns ShortLookupTable (0, blueInvert), null); 

Plakātēšana ir vēl viens jauks efekts, kuru varat izmantot, izmantojot a Meklēt. Plakātu ievietošana ietver attēla parādīšanai izmantoto krāsu skaita samazināšanu.

A Meklēt var sasniegt šo efektu, izmantojot tabulu, kas ievades vērtības kartē ar nelielu izejas vērtību kopu. Šis piemērs parāda, kā ievades vērtības var kartēt ar astoņām īpašām vērtībām.

001 īss [] posterize = jauns īss [256]; 002 (int i = 0; i <256; i ++) 003 posterize [i] = (īss) (i - (i% 32)); 004 BufferedImageOp posterizeOp = 005 new LookupOp (jauns ShortLookupTable (0, posterize), null); 

Sliekšņa noteikšana

Pēdējā attēla darbība, kuru mēs pārbaudīsim, ir sliekšņa noteikšana. Sliekšņa noteikšana padara krāsu izmaiņas pāri programmētāja noteiktai "robežai" vai slieksnim acīmredzamākai (līdzīgi tam, kā kontūras līnijas kartē padara augstuma robežas acīmredzamākas). Šis paņēmiens izmanto noteiktu sliekšņa vērtību, minimālo vērtību un maksimālo vērtību, lai kontrolētu krāsu komponentu vērtības katram attēla pikseļam. Krāsu vērtībām zem sliekšņa tiek piešķirta minimālā vērtība. Vērtībām, kas pārsniedz slieksni, tiek piešķirta maksimālā vērtība.

$config[zx-auto] not found$config[zx-overlay] not found