Εργαλεία Χρήστη

Εργαλεία ιστότοπου


c_image_processing

Σύγκριση εκδόσεων

Εδώ βλέπετε τις διαφορές μεταξύ της επιλεγμένης έκδοσης και της τρέχουσας έκδοσης της σελίδας.

Σύνδεσμος σε αυτή την προβολή διαφορών.

Προηγούμενος έλεγχος και από τις δύο πλευρές Προηγούμενη αναθεώρηση
Επόμενη αναθεώρηση
Προηγούμενη αναθεώρηση
c_image_processing [2014/02/26 12:10]
chiossif
c_image_processing [2020/11/21 09:52] (τρέχουσα)
Γραμμή 2: Γραμμή 2:
  
 Στο wiki αυτό θα μάθουμε να διαχειριζόμαστε και γενικότερα επεξεργαζόμαστε πολυκάναλες εικόνες με την [[https://en.wikipedia.org/wiki/C_%28programming_language%29|γλώσσα προγραμματισμού C]]. Θα ξεκινήσουμε από απλές λειτουργίες όπως ανάγνωση εικόνας και αριθμητική δεικτών και θα προχωρήσουμε σε πιο σύνθετα θέματα :-) Στο wiki αυτό θα μάθουμε να διαχειριζόμαστε και γενικότερα επεξεργαζόμαστε πολυκάναλες εικόνες με την [[https://en.wikipedia.org/wiki/C_%28programming_language%29|γλώσσα προγραμματισμού C]]. Θα ξεκινήσουμε από απλές λειτουργίες όπως ανάγνωση εικόνας και αριθμητική δεικτών και θα προχωρήσουμε σε πιο σύνθετα θέματα :-)
 +
  
  
Γραμμή 9: Γραμμή 10:
 Έτσι, προκειμένου η διαδικασία να γίνει πιο εύκολη, αρκεί να δημιουργηθεί ένα αρχείο που περιέχει μόνο τις τιμές των εικονοστοιχείων και όχι άλλες πληροφορίες που αφορούν το μέγεθος της εικόνας, τον τύπο της κ.τ.λ. Ένα τέτοιο πρότυπο είναι το πρότυπο [[http://users.ntua.gr/chiossif/Free_As_Freedom_Software/BIL_BIP_BSQ.pdf|BIL/BIP/BSQ]] (το οποίο έχουμε μάθει ως .ers) το οποίο μετατρέπει την εικόνα σε δύο αρχεία. Το πρώτο που έχει κατάληξη .ers περιέχει όλες τις πληροφορίες της εικόνας (γραμμές, στήλες, κανάλια, τύπος δεδομένων) και το δεύτερο την εικόνα με τις τιμές της σε όλα τα κανάλια. Έτσι αρκεί, να μετατρέψουμε σε πρώτη φάση την εικόνα μας σε .ers. Η μετατροπή μπορεί να γίνει με πολλούς τρόπους, αλλά ένας από τους πιο εύκολους είναι μέσω της βιβλιοθήκης gdal. Η [[http://www.gdal.org/|gdal]] είναι μια βιβλιοθήκη ελεύθερου λογισμικού που χρησιμοποιείται για γεωχωρικά δεδομένα και υποστηρίζει όλα τα πρότυπα στα οποία μπορεί να έχει αποθηκευτεί μια εικόνα. Έτσι, προκειμένου η διαδικασία να γίνει πιο εύκολη, αρκεί να δημιουργηθεί ένα αρχείο που περιέχει μόνο τις τιμές των εικονοστοιχείων και όχι άλλες πληροφορίες που αφορούν το μέγεθος της εικόνας, τον τύπο της κ.τ.λ. Ένα τέτοιο πρότυπο είναι το πρότυπο [[http://users.ntua.gr/chiossif/Free_As_Freedom_Software/BIL_BIP_BSQ.pdf|BIL/BIP/BSQ]] (το οποίο έχουμε μάθει ως .ers) το οποίο μετατρέπει την εικόνα σε δύο αρχεία. Το πρώτο που έχει κατάληξη .ers περιέχει όλες τις πληροφορίες της εικόνας (γραμμές, στήλες, κανάλια, τύπος δεδομένων) και το δεύτερο την εικόνα με τις τιμές της σε όλα τα κανάλια. Έτσι αρκεί, να μετατρέψουμε σε πρώτη φάση την εικόνα μας σε .ers. Η μετατροπή μπορεί να γίνει με πολλούς τρόπους, αλλά ένας από τους πιο εύκολους είναι μέσω της βιβλιοθήκης gdal. Η [[http://www.gdal.org/|gdal]] είναι μια βιβλιοθήκη ελεύθερου λογισμικού που χρησιμοποιείται για γεωχωρικά δεδομένα και υποστηρίζει όλα τα πρότυπα στα οποία μπορεί να έχει αποθηκευτεί μια εικόνα.
  
-Έχοντας λοιπόν την [[ https://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png|εικόνα]] μας την μεταφορτώνουμε με την εντολή:+Έχοντας λοιπόν την [[https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png |εικόνα]] μας την μεταφορτώνουμε με την εντολή:
  wget https://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png  wget https://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png
 και μέσω της gdal την μετατρέπουμε σε ers πρότυπο και μέσω της gdal την μετατρέπουμε σε ers πρότυπο
Γραμμή 194: Γραμμή 195:
 -> Ο συνδυασμός των παραπάνω τεχνικών δήλωσης και κατάληψης μνήμης επιτρέπει την άμεση διευθυνσιοδότηση χωρίς αριθμητική δεικτών. -> Ο συνδυασμός των παραπάνω τεχνικών δήλωσης και κατάληψης μνήμης επιτρέπει την άμεση διευθυνσιοδότηση χωρίς αριθμητική δεικτών.
    
 +
 +
  
  
Γραμμή 224: Γραμμή 227:
 και την χρησιμοποιώ έτσι:  και την χρησιμοποιώ έτσι: 
     IMAGE_PIXEL(i,j,k)     IMAGE_PIXEL(i,j,k)
 +
 +Παράδειγμα [[http://stackoverflow.com/questions/1616802/when-to-use-function-like-macros-in-c|μακροεντολής]]:
 +    #define IMAGE_PIXEL(x,y,z) (image [(((x)*bands)+(y))*cols+(z)])
 +
 +και παράδειγμα συνάρτησης:
 +    char image_pixel(int x, int y, int z){
 +     return (image [(((x)*bands)+(y))*cols+(z)]);
 +    }
  
 Προσοχή θέλουν εδώ τα ονόματα των εμπλεκομένων μεταβλητών καθώς και η [[http://www.tutorialspoint.com/cprogramming/c_scope_rules.htm|ορατότητά]] τους. Την 2η έκδοση την χρησιμοποιώ όταν φτιάχνω ένα λογισμικό με πολλές αναφορές στην εικόνα και θέλω να είναι ευανάγνωστο. Δυστυχώς εδώ θέλει πολύ προσοχή η σωστή δήλωση των μεταβλητών και η κατάληψη της μνήμης. Τέλος, και για να δώσω την σωστή/αληθινή απάντηση, καμιά από τις δύο. Διότι σε αυτές η εικόνα πρέπει να έρθει όλη στην μνήμη και άρα η μνήμη του υπολογιστή είναι ένα όριο για το μέγεθος της εικόνας. Ακολουθεί καλύτερο παράδειγμα με άλγεβρα εικόνων χωρίς αυτό τον περιορισμό ;-) Προσοχή θέλουν εδώ τα ονόματα των εμπλεκομένων μεταβλητών καθώς και η [[http://www.tutorialspoint.com/cprogramming/c_scope_rules.htm|ορατότητά]] τους. Την 2η έκδοση την χρησιμοποιώ όταν φτιάχνω ένα λογισμικό με πολλές αναφορές στην εικόνα και θέλω να είναι ευανάγνωστο. Δυστυχώς εδώ θέλει πολύ προσοχή η σωστή δήλωση των μεταβλητών και η κατάληψη της μνήμης. Τέλος, και για να δώσω την σωστή/αληθινή απάντηση, καμιά από τις δύο. Διότι σε αυτές η εικόνα πρέπει να έρθει όλη στην μνήμη και άρα η μνήμη του υπολογιστή είναι ένα όριο για το μέγεθος της εικόνας. Ακολουθεί καλύτερο παράδειγμα με άλγεβρα εικόνων χωρίς αυτό τον περιορισμό ;-)
Γραμμή 378: Γραμμή 389:
  
 -> Προσέξτε πως ελέγχουμε την απόδοση τιμής στο αποτέλεσμα. Μην ξεχνάμε πως προδιαγραφή (και άρα περιορισμός) είναι η εικόνα αποτέλεσμα να είναι 8bit όπως και η εικόνα εισόδου. Αυτό το λογισμικό αντιμετωπίζει μόνο εικόνες 8bit και έτσι πρέπει να έχει τιμές στο εύρος [0,255] (unsigned char). -> Προσέξτε πως ελέγχουμε την απόδοση τιμής στο αποτέλεσμα. Μην ξεχνάμε πως προδιαγραφή (και άρα περιορισμός) είναι η εικόνα αποτέλεσμα να είναι 8bit όπως και η εικόνα εισόδου. Αυτό το λογισμικό αντιμετωπίζει μόνο εικόνες 8bit και έτσι πρέπει να έχει τιμές στο εύρος [0,255] (unsigned char).
 +
 +
 +
 +
 +
 +
  
 ====Ερωτήσεις==== ====Ερωτήσεις====
  
-Αναμένω τις ερωτήσεις σας :-)+* Ερ.: Έχουμε δύο εικόνες με ένα κανάλι και ίδιες διαστάσεις από το ίδιο αντικείμενο/περιοχή και θέλουμε να δούμε οπτικά την ταύτισή τους με την μορφή σκακιέρας: στα άσπρα τετράγωνα η μία στα μαύρα η άλλη. Δεδομένα μας είναι τα ονόματα των αρχείων των εικόνων σε ERS φορμάτ άρα και οι γραμμές και οι στήλες τους, το όνομα της εικόνας σκακιέρας και φυσικά το μέγεθος του τετραγώνου της σκακιέρας. Υποδ. Ξεκινήστε αυτό το πρόγραμμα με χρήση του παραπάνω κώδικα. Στην απάντηση τεκμηριώστε τις κύριες αλλαγές ενώ μέσα στον κώδικα προσθέστε σχόλια :-)
  
 +* Απ.: Χρησιμοποιώντας τον παραπάνω κώδικα έγιναν δύο βασικές αλλαγές. Η πρώτη αφορά στα δεδομένα τα οποία χρειάζονται και πρέπει να διαβαστούν και η δεύτερη στη συνθήκη η οποία θα υλοποιήσει το επιθυμητό αποτέλεσμα. Συγκεκριμένα, σε αυτήν την περίπτωση έχουμε εικόνες με ένα κανάλι και όχι rgb,  οπότε απλοποιείται η διαδικασία του διαβάσματος. Επίσης, έπρεπε να προστεθεί μια μεταβλητή για το μέγεθος του τετραγώνου της σκακιέρας η ssize.  
 +
 +Το πρόγραμμα διαβάζει τις εικόνες σε τυποποίηση ERS. Για τη μετατροπή αυτή έχει χρησιμοποιηθεί η ακόλουθη εντολή από τερματικό :
 +    gdal_translate -of ers -ot byte -strict -scale -b 1 input.tif input.ers
 +
 +σε σύστημα με εγκατεστημένη την βιβλιοθήκη gdal.
 +
 +Την υλοποίηση θα την βρείτε στον σύνδεσμο [[https://dl.dropboxusercontent.com/u/1145459/skakiera.c|αυτό]] και είναι ανάλογη με το παράδειγμα παραπάνω. Η κύρια λειτουργία εκτελείται στην γραμμή:
 +
 +    image_out[k]=((i/ssize-k/ssize)%2)?image_in1[k]:image_in2[k];
 +
 +όπου με τον τελεστή ()?: αποφασίζεται και αποθηκεύεται στην εικόνα αποτέλεσμα image_out στην θέση k (πρόκειται για ενδιάμεση μνήμη αποθήκευσης μιας γραμμής) είτε η image_in1 είτε η image_in2. Η απόφαση λαμβάνεται από το λογικό (i/ssize-k/ssize)%2 όπου i η τρέχουσα γραμμή η οποία περιέχεται στις ενδιάμεσες μνήμες των εικόνων, k η τρέχουσα στήλη (ως στοιχείο των ενδιάμεσων μνημών) και ssize το μέγεθος του τετράγωνου της σκακιέρας όπως προαναφέρθηκε. :-)
  
 ====Ασκήσεις==== ====Ασκήσεις====
Γραμμή 397: Γραμμή 426:
  
  
-=====Φιλτράρισμα σε εικόνα με ενδιάμεση αποθήκευση===== 
  
-Τώρα με την μονόχρωμματική Λέννα μπορούμε να συνεχίσουμε :-)+ 
 + 
 +=====Φιλτράρισμα σε εικόνα===== 
 + 
 +Στην προηγούμενη εφαρμογή φτιάξαμε μία μονοκάναλη εικόνα με εφαρμογή πράξεων σε πολυκάναλη (άλγεβρα εικόνων). Μια και την έχουμε λοιπόν ας κάνουμε ένα απλό φίλτρο με την τεχνική της [[http://rosettacode.org/wiki/Image_convolution|συνέληξης]].   
  
     #include <stdio.h> /* FILE, printf, fopen, fscanf, fclose, fread, fwrite  */     #include <stdio.h> /* FILE, printf, fopen, fscanf, fclose, fread, fwrite  */
Γραμμή 549: Γραμμή 582:
     }     }
  
-Μόλις είδαμε μια εφαρμογή για φιλτράρισμα εικόνας με κυλιόμενη ενδιάμεση μνήμη προσωρινής αποθήκευσης. Μελετήστε το και επανέρχομαι ;-)+Μόλις είδαμε μια εφαρμογή για φιλτράρισμα εικόνας με κυλιόμενη ενδιάμεση μνήμη προσωρινής αποθήκευσης. Ας το δούμε πιο προσεκτικά (αν και όχι τόσο αναλυτικά - μελετήστε...): 
 + 
 +-> Χρησιμοποίησα πίνακα δεικτών για να αποθηκεύσω το φίλτρο στην μνήμη αλλά για την εικόνα εισόδου και εξόδου έναν πίνακα για κάθε μία και αριθμητική δεικτών για την προσπέλαση. 
 + 
 +-> Δεν διαβάζω όλη την εικόνα στην μνήμη αλλά αντίθετα κρατάω μόνο το πλήθος των γραμμών που είναι απαραίτητες για να εκτελεστεί το φίλτρο. Έτσι υπολογίζω μία γραμμή στην εικόνα εξόδου κάθε φορά και αυτήν αποθηκεύω γραμμή γραμμή. Με αυτό τον τρόπο πετυχαίνω οικονομία μνήμης και παράλληλα εξασφαλίζω ότι και υπολογιστές με μικρή σχετικά μνήμη θα είναι ικανοί να εκτελέσουν αυτήν την επεξεργασία με πολύ μεγάλες εικόνες (αυτό το πρόγραμμα έχει δοκιμαστεί σε εικόνα 4096x4096 pixels ενώ δεν δημιουργείται θέμα και με πολλαπλάσια μεγέθη). 
 + 
 +-> Προσέξτε τον τρόπο με τον οποίο «κυλάω» τις παλαιότερες γραμμές στην μνήμη προς τα «πάνω» και διαβάζω μία νέα γραμμή στην θέση της τελευταίας. Έτσι και ενώ σαρώνω γραμμή γραμμή το αρχείο εισόδου ελαχιστοποιώ την επαφή με τον δίσκο για μέγιστη ταχύτητα. 
 + 
 +Ομολογουμένως έχει μια πολυπλοκότητα αλλά είναι τόσα τα πλεονεκτήματα χρήσης που πραγματικά αξίζει τον κόπο. Τέτοιες τεχνικές,  οι οποίες εξασφαλίζουν προγράμματα ταχύτατα και με ελάχιστες απαιτήσεις στην μνήμη, προγραμματίζονται σήμερα σε όλο και πιο πολύπλοκες εφαρμογές και με όλο και πιο αυξημένες απαιτήσεις επεξεργαστικής ισχύος. Όσοι προγραμματίζουν ανάλογες εφαρμογές σε γλώσσα προγραμματισμού C, θα πρέπει να έχουν αυτές τις τεχνικές στην προγραμματιστική τους ατζέντα ;-)  
 + 
 +Το αρχείο φίλτρου με το οποίο δοκιμάσαμε τον παραπάνω κώδικα έχει σαν περιεχόμενα: 
 + 
 +    3 3 
 +     0 -1  0 
 +    -1  5 -1 
 +     0 -1  0 
 +    1.0 
 + 
 +όπου 3 3 είναι οι διαστάσεις του φίλτρου, ακολουθεί ο πίνακας συνέλιξης και τέλος ο διαιρέτης του φίλτρου. 
 + 
 +Η εκτέλεση έγινε ανάλογα με την προηγούμενη εφαρμογή της άλγεβρας εικόνας με τις ακόλουθες εντολές: 
 +    gcc Filter.c 
 +    ./a.out Lenna_MONO 512 512 Lenna_HIGH filter.txt 
 +    gdal_translate -of PNG Lenna_HIGH.ers Lenna_HIGH.png 
 + 
 +====Ερωτήσεις==== 
 + 
 +Μελετήστε τον κώδικα και αναμένουμε τις ερωτήσεις σας :-) 
 + 
 + 
 + 
 +====Ασκήσεις==== 
 + 
 +Με βάση την εφαρμογή φιλτραρίσματος εικόνας σας προτείνουμε να γράψετε / μετατρέψετε το παραπάνω ώστε να: 
 + 
 +* εκτελεί φίλτρα ανίχνευσης ακμών σαν το Sobel, Prewitt και Kirsch 
 + 
 +* λειτουργεί με εικόνες 16bit 
 + 
 +* λειτουργεί για ένα ή περισσότερα κανάλια σε πολυφασματική εικόνα 
 + 
 +Θυμίζουμε ξανά την χρήση του προτύπου ers και της gdal για την μετατροπή των εικόνων. :-) 
 + 
 + 
 + 
 + 
 + 
 + 
 +=====Παράλληλος προγραμματισμός στην επεξεργασία εικόνας===== 
 + 
 +Μαθαίνουμε επεξεργασία εικόνας σε C και είδαμε μέχρι εδώ πως να δουλεύουμε με τεράστιες εικόνες διαβάζοντας μόνο ότι είναι απαραίτητο σε κάθε ανακύκλωση. Αν όμως η εικόνα χωράει στην μνήμη; Πως μπορούμε να κάνουμε επεξεργασίες με την μεγαλύτερη δυνατή ταχύτητα; Την απάντηση εδώ μας την δίνει ο παράλληλος προγραμματισμός. :-) 
 + 
 +Οι σύγχρονοι επεξεργαστές περιέχουν πολλούς πυρήνες και έτσι έχουν την δυνατότητα να εκτελέσουν πολλές διεργασίες ταυτόχρονα αρκεί η μία να μην εξαρτάται από την άλλη. Στην περίπτωση των εικόνων αυτό είναι εφικτό με την τμηματική εκτέλεση μιας εικόνας. Αν για παράδειγμα έχουμε τετραπύρηνο επεξεργαστή μπορούμε να κόψουμε μια εικόνα στα τέσσερα (σταυρό) και να δώσουμε κάθε κομμάτι σε κάθε πυρήνα. Φυσικά ο προγραμματισμός σε αυτή την περίπτωση θα ήταν περίπλοκος. 
 + 
 +Σήμερα χάρη στην [[http://openmp.org/wp/about-openmp/|OpenMP]] μπορούμε με ελάχιστες αλλαγές να προγραμματίσουμε παράλληλα. Δείτε το ακόλουθο πρόγραμμα το οποίο εφαρμόζει το φίλτρο [[https://en.wikipedia.org/wiki/Kirsch_operator|Kirsch]] σε μία μονοχρωμματική εικόνα:  
 + 
 +  #include <stdio.h> /* FILE, EOF, printf(), fread(), fwrite(), fclose() */ 
 +  #include <stdlib.h> /* exit(), malloc(), atoi(), free() */ 
 +  #include <string.h> /* memcpy(), atoi() */ 
 +  #include <omp.h> /* #pragma omp parallel */ 
 +   
 +  int main(int argc, char **argv){ 
 + FILE *fp; 
 + int rows, cols, rows_1, cols_1, kirsch, a[15], t; 
 + unsigned char *image_in, *image_out; 
 + register i, j, k; 
 +   
 + if (argc!=5){ 
 + printf("Usage: $Kirsch InputImageFile Rows Columns OutputImageFile\n"); 
 + exit(1); 
 +
 + if ((fp=fopen(argv[1],"rb"))==NULL){ 
 + printf("Error: Bad InputImageFile: <%s>\n",argv[1]); 
 + exit(1); 
 +
 + rows=atoi(argv[2]); 
 + cols=atoi(argv[3]); 
 + if (rows<1){ 
 + printf("Error: Bad rows value: <%s>\n",argv[2]); 
 + exit(1); 
 +
 + if (cols<1){ 
 + printf("Error: Bad columns value: <%s>\n",argv[3]); 
 + exit(1); 
 +
 + if ((image_in=malloc(rows*cols*sizeof(char)))==NULL){ 
 + printf("Error: Not enough memory available\n"); 
 + exit(1); 
 +
 + if ((image_out=malloc(rows*cols*sizeof(char)))==NULL){ 
 + printf("Error: Not enough memory available\n"); 
 + exit(1); 
 +
 + if ((image_in=malloc(rows*cols*sizeof(char)))==NULL){ 
 + printf("Error: Not enough memory available\n"); 
 + exit(1); 
 +
 +   
 + if (fread(image_in,sizeof(char),rows*cols,fp)!=rows*cols){ 
 + printf("Error: Input file size does not match image dimensions\n"); 
 + exit(1); 
 +
 + if (fclose(fp)==EOF){ 
 + printf("Error: Bad file closing\n"); 
 + exit(1); 
 +
 +   
 + rows_1=rows-1; 
 + cols_1=cols-1; 
 +   
 +  { // START parallel  
 +  #pragma omp parallel for  private(i, j, k, a, t, kirsch) 
 + for (i=1;i<rows_1;i++){ 
 + for (j=1;j<cols_1;j++){ 
 + a[0]=image_in[ (i-1) * cols + j-1 ]; 
 + a[1]=image_in[ (i-1) * cols + j   ]; 
 + a[2]=image_in[ (i-1) * cols + j+1 ]; 
 + a[3]=image_in[  i    * cols + j+1 ]; 
 + a[4]=image_in[ (i+1) * cols + j+1 ]; 
 + a[5]=image_in[ (i+1) * cols + j   ]; 
 + a[6]=image_in[ (i+1) * cols + j-1 ]; 
 + a[7]=image_in[  i    * cols + j-1 ]; 
 + a[8] =a[0]; 
 + a[9] =a[1]; 
 + a[10]=a[2]; 
 + a[11]=a[3]; 
 + a[12]=a[4]; 
 + a[13]=a[5]; 
 + a[14]=a[6]; 
 + kirsch=0; 
 + for (k=0;k<8;k++){ 
 + t=(5.0*(a[k]+a[k+1]+a[k+2])-3.0*(a[k+3]+a[k+4]+a[k+5]+a[k+6]+a[k+7]))*256.0/3826.0; /* 255*3*5=3825 */ 
 + if (t>kirsch) 
 + kirsch=t; 
 +
 + image_out [ i * cols + j ] = kirsch; 
 +
 + image_out[i*cols+0]=image_out[i*cols+1]; 
 + image_out[i*cols+cols_1]=image_out[i*cols+cols-2]; 
 +
 +  } // END parallel 
 + memcpy(&image_out[0], &image_out[cols], cols); 
 + memcpy(&image_out[rows_1*cols], &image_out[(rows-2)*cols], cols); 
 +   
 + if ((fp=fopen(argv[4],"wb"))==NULL){ 
 + printf("Error: Bad OutputImageFile: <%s>\n",argv[4]); 
 + exit(1); 
 +
 + if (fwrite(image_out,sizeof(char),rows*cols,fp)!=rows*cols){ 
 + printf("Error: Bad write to OutputImageFile\n"); 
 + exit(1); 
 +
 + if (fclose(fp)==EOF){ 
 + printf("Error: Bad file closing\n"); 
 + exit(1); 
 +
 + free(image_in); 
 + free(image_out); 
 + return 0; 
 +  }
  
  
 +Για το φίλτρο [[https://en.wikipedia.org/wiki/Kirsch_operator|Kirsch]] δεν θα γράψουμε τίποτε. Μελετήστε τον ορισμό του και την υλοποίησή του :-)
 +Αλλά ούτε και για την παραλληλοποίηση της εκτέλεσης του φίλτρου θα γράψουμε κάτι. Απλά δείτε: τι κάνει το πρόγραμμά μας παράλληλο; Οι ακόλουθες γραμμές:
  
 +  ...
 +  #include <omp.h> /* #pragma omp parallel */
 +  ...
 +  { // START parallel 
 +  #pragma omp parallel for  private(i, j, k, a, t, kirsch)
 +  ...
 +  } // END parallel
 +  ...
 +και φυσικά μεταγλώττιση με την παράμετρο -fopenmp στην gcc ;-)
 +Δοκιμάστε το στην Lenna_Grey.ers με την εντολή:
 +  ./a.out Lenna_Grey 512 512 Lenna_Kirsch
 +Στιγμιαίο έτσι; Όπως θα ήταν και χωρίς τις παραπάνω παράλληλες ρυθμίσεις. Ναι αλλά η Lenna_Grey είναι μικρή. Για δοκιμάστε με μία εικόνα 5120x5120 ή μεγαλύτερη και τα συζητάμε ;-)
  
-πό σύνταξη ;-) )    +Περισσότερα για παράλληλο προγραμματισμό θα βρείτε στον ιστοχώρο της [[https://computing.llnl.gov/tutorials/openMP/|OpenMP]] και γενικότερα [[https://computing.llnl.gov/tutorials/parallel_comp/|εδώ]]. Πάντως εδώ δεν θα συνεχίσουμε άλλο...
  
 +Ελπίζω η σπίθα να άναψε ;-)
  
 +Καλή παραλληλοποίηση ;-)
  
 =====Επίλογος===== =====Επίλογος=====
c_image_processing.1393416647.txt.gz · Τελευταία τροποποίηση: 2020/11/21 09:52 (εξωτερική τροποποίηση)