Forelsning Uge 3 Torsdag Billedredigering Grtonebilleder som er
Forelæsning Uge 3 – Torsdag • Billedredigering – Gråtonebilleder (som er lidt simplere end farvebilleder) • Rekursive metoder – Metoder kalder sig selv – Giver ofte meget elegante og simple løsninger på komplekse problemer • Refaktorering – Vi vil omstrukturere Music. Organizer – Et musiknummer repræsenteres nu ved hjælp af en Track klasse (i stedet for en tekststreng) • Iterator typen – Endnu en måde at gennemløbe en objektsamling • Afleveringsopgave: Skildpadde 2 (Turtle 2)
Om programmering • Programmering Giv ikke op – Fortvivl ikke Tingene ændrer sig hurtigt – Anderledes – Ny tankegang Begejstring • Faser – – – – – Motivation Begejstring Tvivl? Frustration Eksistentiel krise Heureka! Fascination Indsigt Magt over teknologien • Hurra! Tid – Programmering er sjovt og stærkt vanedannende – Når man først kommer godt i gang, kan det være svært at stoppe igen 2
● Billedredigering Lysere Mørkere Inverteret Uskarpt 3
Repræsentation af billede 0 0 x width Gråtoneværdi: Pixel (x, y) [0. . 255] hvor 0 ~ sort og 255 ~ hvid y height 4
Image og Pixel klasserne • Vi bruger to klasser – Image repræsenterer et billede og har metoder, som arbejder på billedet, bl. a. brighten, darken, invert og blur – Pixel repræsenterer en enkelt pixel og har metoder til at aflæse og sætte pixlens gråtoneværdi Image Pixel * én-til-mange relation public class Pixel { private int value; // Pixlens gråtoneværdi [0, 255] // Konstruktøren initialiserer gråtoneværdien public Pixel(int value) {. . . } // Returnerer gråtoneværdien for denne pixel public int get. Value() {. . . } } // Opdaterer gråtoneværdien for denne pixel public void set. Value(int value) {. . . } 5
Interface for Image klassen (signaturer) public class Image {. . . // Returnerer billedets bredde public int get. Width() {. . . } // Returnerer billedets højde public int get. Height() {. . . } Udvalgte metoder // Returnerer pixlen på position (x, y) public Pixel get. Pixel(int x, int y) {. . . } // Returnerer en liste med samtlige pixels i billedet public Array. List<Pixel> get. Pixels() {. . . } // Returnerer de op til ni naboer til (x, y) (inklusiv (x, y)) public Array. List<Pixel> get. Neighbours(int x, int y) {. . . } // Gentegner billedet public void update. Canvas() {. . . } 6
Skabelon for simpel billedoperation image • Vi bruger en for-each løkke til at gennemløbe samtlige pixels og opdatere dem en efter en – Rækkefølgen er ligegyldig for os Erklæring af lokal variabel Den arrayliste der skal gennemløbes for( Pixel p : image. get. Pixels() ) { int old. Value = p. get. Value(); int new. Value = ? ? ? ; p. set. Value(new. Value); find værdien af p } opdater p's værdi beregn ny værdi ud fra den gamle p 7
Brighten (lysere) new. Value = old. Value + 30 0 ~ sort, 255 ~ hvid 8
Brighten, Javakode image for( Pixel p : image. get. Pixels() ) { int old. Value = p. get. Value(); int new. Value = old. Value + 30 ; p. set. Value(new. Value); } for( Pixel p : image. get. Pixels() ) { p. set. Value(p. get. Value() + 30); } Kan I se et potentielt problem? p set. Value metoden sørger for at værdien ligger i intervallet [0, 255] 9
Invert (byt om på sort og hvid) new. Value = 255 - old. Value 10
Invert, Javakode image for( Pixel p : image. get. Pixels() ) { int old. Value = p. get. Value(); int new. Value = 255 – old. Value ; p. set. Value(new. Value); } for( Pixel p : image. get. Pixels() ) { p. set. Value(255 - p. get. Value()); } p 11
Eksempler på billedoperationer brighten darken invert blur Gør billedet lidt lysere Gør billedet lidt mørkere Inverterer hver gråtone Erstatter hver pixel med gennemsnittet af naboerne mirror flip rotate resize Spejler billedet om den vertikale midterakse Spejler billedet om den horisontale midterakse Roterer billedet 90 grader med uret Skalerer billedet, så størrelsen ændres I den anden afleveringsopgave i uge 4 skal I implementere disse operationer Clicker Quiz 12
● Rekursive metoder • Fakultets funktionen n! er defineret ved n! = 1 * 2 *. . . * (n-1) * n 5! = 1 * 2 * 3 * 4 * 5 = 120 for n ≥ 1 1! = 1 • Beregning ved hjælp af en for-løkke public int faculty(int n) { int result = 1; for(int i = 2; i <= n; i++) { result *= i; } return result; } 13
Fakultets funktionen (rekursiv) • Fakultets funktionen kan også defineres rekursivt, dvs. ved hjælp af sig selv 0! = 1 1! = 1 n! = (n-1)! * n 24 * 5 = 120 for n > 1 • Rekursiv metode til beregning af n! public int faculty(int n) { if(n == 0) { return 1; } if(n == 1) { return 1; } return faculty(n-1) * n; } Rekursion ≈ Induktionsbeviser faculty(5) 6 * 4 = 24 faculty(4) 2*3=6 faculty(3) 1*2=2 faculty(2) 1 faculty(1) Vores Sudoku-løser bruger rekursion Vi placerer ét ciffer, hvorefter vi laver et rekursivt kald, der placerer det næste Hvad sker der, hvis metoden kaldes med en negativ parameterværdi? 14
Fibonacci tallene • Nedenstående talfølge, hvor hvert tal er lig summen af de to foregående 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, … • Beregning ved hjælp af en for-løkke public int fibonacci. Loop(int n) { if(n == 1) { return 0; } int first = 0; int second = 1; int temp; for(int i = 3; i <= n; i++) { temp = second; second += first; first = temp; } return second; } Lidt svær at gennemskue, hvad der sker i løkken 15
Fibonacci funktionen (rekursiv) • Rekursiv definition fib(1) = 0 fib(2) = 1 fib(n) = fib(n-2) + fib(n-1) for n ≥ 3 • Rekursiv beregning public int fibonacci(int n) { if(n == 1) { return 0; } if(n == 2) { return 1; } return fibonacci(n-2) + fibonacci(n-1); } • Elegant, men ikke effektivt fibonacci(5) Samme værdi beregnes mange gange fibonacci(3) + fibonacci(4) fibonacci(1) + fibonacci(2) Rekursion er utrolig nyttigt og anvendes meget fibonacci(2) + fibonacci(3) fibonacci(1) + fibonacci(2) 16
Palindrom • Nedenstående metode tjekker om parameteren er et palindrom, dvs. er ens forfra og bagfra (fx "kik", "anna", "p" og "") Java API – – Den bruger tre metoder fra String klassen length() returnerer længden af strengen char. At(int i) returnerer det tegn (af typen char), der er i index i substring(int i 1, int i 2) returnerer den delstreng, der starter i index i 1 og slutter i index i 2 – 1 public boolean palindrome(String s) { int length = s. length(); if(length <= 1) { return true; } // Divide string char first = s. char. At(0); char last = s. char. At(length-1); String middle = s. substring(1, length-1); } if(first == last) { return palindrome(middle); } else { return false; } // Recursive call Pause 17
● Refaktorering af Music. Organizer • I første version af Music. Organizer har vi repræsenteret et musiknummer ved hjælp af en tekststreng – Nu vil vi indføre en klasse Track som modellerer musiknumre – På den måde kan vi bedre skelne mellem de enkelte elementer, f. eks. navnet på artisten og navnet på musiknummeret Track Feltvariabler Accessor metoder String artist String title String filename. . . String get. Artist() String get. Title() String get. Filename() Det er Track klassens ansvar at kunne generere en String repræsentation af objektets tilstand RESPONSIBILITY DRIVEN DESIGN String get. Details() Mutator metode set. Details(String a, String t, String f) 18
Vi kan nu lave mere præcise søgninger • Find et musiknummer, hvor titlen indeholder en bestemt tekststreng public Track find. In. Title(String q) { } for(Track t : tracks) { if(t. get. Title(). contains(q)) { return t; } • Ifølge Blue. J bogen bør man kun bruge for-each } løkker, når man vil gennemløbe hele arraylisten return null; • Jeg har intet problem med, at man afbryder gennemløbet undervejs, når man har fundet man søger • Metoden øverst side 301 er et typisk eksempel på find. One – og her afbrydes gennemløbet! • Find alle musiknumre, hvor kunstnernavnet indeholder en bestemt tekststreng public Array. List<Track> find. By. Artist(String q) { Array. List<Track> result = new Array. List<>(); } for(Track t : tracks) { if(t. get. Artist(). contains(q)) { result. add(t); } } return result; 19
Refaktorering (omstrukturering) • På de foregående slides har vi foretaget en refaktorering af arkitekturen for Music. Orgnizer – Vi har erstattet brugen af tekststrenge til repræsentation af musiknumre med Track klassen – som giver en bedre og mere detaljeret beskrivelse af musiknumres egenskaber – Andre eksempler på refaktorering vil være opdeling af en klasse, der er blevet meget stor eller indeholder metoder, der ikke naturligt hører sammen • Under udviklingen af et system er der ofte behov for at lave refaktorering – Når man refaktorerer ændrer man systemets arkitektur uden at ændre dets opførsel – Efter refaktoreringen tester man, at det nye program virker på samme måde som det gamle – Først derefter tilføjer man ny funktionalitet 20
Forskellige former for gennemløb • Når vi har en arrayliste kan vi gennemløb elementerne på forskellige vis Hjælpemetode for-each løkke for( String s : list) { print(s); } private void print(String s) { System. out. println(s); } for løkke for( int i = 0; i < list. size(); i++ ) { print(list. get(i)); } while løkke int i = 0; while( i < list. size() ) { print(list. get(i)); i++; } Iterator + while løkke import java. util. Iterator; Clicker Quiz Hvorfor bruge Iterator? • Mere kompliceret end de andre • Men den har nogle fordele Iterator<String> it = list. iterator(); while( it. has. Next() ) { print(it. next()); } 21
● Iteratorer typen • Iterator typen indeholder faciliteter til gennemløb af en objektsamling (f. eks. en arrayliste) – Metoden has. Next() returnerer en boolsk værdi, som indikerer, om der er flere elementer at besøge – Metoden next() returnerer det næste element i objektsamlingen – "Flytter" samtidig iteratoren – således at næste kald af next() returnerer det efterfølgende element i objektsamlingen – Hvis has. Next() returnerer false, vil et kald af next() generere en runtime fejl • Alle collection typer har en iterator – Man får fat i et iterator objekt ved at kalde metoden iterator() Importer Iterator klassen Erklær lokal variabel it (reference til en iterator for den objektsamling, som list peger på) Brug iteratorens metoder import java. util. Iterator; . . . Parametriseret type Iterator<String> it = list. iterator(); . . . while( it. has. Next() ) { print( it. next() ); }. . . 22
Hvorfor bruge en iterator? • Iteration ved hjælp af en iterator er mere kompliceret end iteration ved hjælp af for-each, for og while løkker – Hvorfor så overhovedet bruge Iterator? • Nogle collection typer mangler et index begreb (det gælder f. eks. mængder og træer) – Man har så behov for en anden måde at tilgå elementerne – Det kan man ved hjælp af en iterator • Man kan have behov for at fjerne elementer i den objektsamling, som man er i færd med at gennemløbe – Hvis man kalder objektsamlingens remove metode under et gennemløb af en for-each løkke får man en runtime fejl – Hvis man gør det inde i en for eller while løkke, går der let "koks" i iterationen (fordi indices ændres undervejs) • Iterator klassen har en metode remove(), som tillader, at man fjerner det element, som sidste kald af next() returnerede – Denne metode kan anvendes inde i while og do-while løkker 23
● Afleveringsopgave: Skildpadde 2 (Turtle 2) I Skildpadde 1 tegnede i forskellige figurer i stil med nedenstående Nu skal I, ved hjælp af rekursive metoder, tegne mere komplekse figurer i stil med nedenstående 24
1) ch 1) Ko (n- n=1 n≥ 1 Ko Koch(n) ch n=0 (n- Koch kurver En Koch kurve af grad n (hvor n > 0) kan tegnes ved at tegne fire Koch kurver af grad n-1 Koch(n-1) size n=2 n=3 n=4 n=5 Rekursiv metode public void koch. Curve(int n, double size) { if( n > 0 ) { koch. Curve(n-1, ……); turn(……); koch. Curve(n-1, ……); } else { move(size); } } 25
Sierpinksi kurver En Sierpinksi kurve af grad n (hvor n > 0) kan tegnes ved at tegne tre Sierpinski kurver af grad n-1 size Sier(n-1) n=0 n≥ 1 Sierpinksi(n) Sier(n-1) n=1 n=2 n=3 Rekursiv metode public void sierpinski. Curve(int n, double size) { if( n > 0 ) { sierpinski. Curve(n-1, ……); // Draw first triangle ……………… // Go to start position for second triangle sierpinski. Curve(n-1, ……); // Draw second triangle ……………… // Go to start position for third triangle sierpinski. Curve(n-1, ……); // Draw third triangle ……………… // Go back to start position and start angle } else { Vigtigt at man husker at gå tilbage triangle(size); til udgangsposition og -vinkel } } 26
● Opsummering • Billedredigering – Gråtonebilleder (som er lidt simplere end farvebilleder) • Rekursive metoder I den anden afleveringsopgave i uge 4 skal I arbejde med billedredigering – Metoder kalder sig selv – Giver ofte meget elegante og simple løsninger på komplekse problemer • Refaktorering – Vi omstrukturerede Music. Organizer – Et musiknummer repræsenteres nu ved hjælp af en Track klasse (i stedet for en tekststreng) • Iterator typen – Ny måde at gennemløbe en objektsamling • Afleveringsopgave: Skildpadde 2 (Turtle 2) 27
Det var alt for nu…. . … spørgsmål 28
- Slides: 28