Απλή Ζωή

Πλήρης οδηγός για αλγόριθμους ανίχνευσης ακμών

Εισαγωγή

Η επεξεργασία εικόνας είναι μια ευρέως χρησιμοποιούμενη έννοια για την εκμετάλλευση των πληροφοριών από τις εικόνες. Οι αλγόριθμοι επεξεργασίας εικόνας χρειάζονται πολύ χρόνο για να επεξεργαστούν τα δεδομένα λόγω των μεγάλων εικόνων και του όγκου των πληροφοριών που είναι διαθέσιμες σε αυτές. Έτσι, σε αυτές τις τεχνικές κοπής άκρων, είναι απαραίτητο να μειωθεί ο όγκος των πληροφοριών στις οποίες θα πρέπει να επικεντρωθεί ο αλγόριθμος. Μερικές φορές αυτό μπορούσε να γίνει μόνο περνώντας τις άκρες της εικόνας. Έτσι, σε αυτό το ιστολόγιο ας κατανοήσουμε τον ανιχνευτή άκρων Canny και τον ανιχνευτή ακμών Holistically Nested.

Τι είναι η ανίχνευση άκρων;

Ένα άκρο σε μια εικόνα είναι μια σημαντική τοπική αλλαγή στην ένταση της εικόνας. Όπως υποδηλώνει το όνομα, η ανίχνευση άκρων είναι η διαδικασία ανίχνευσης των άκρων σε μια εικόνα. Το παρακάτω παράδειγμα απεικονίζει μια ανίχνευση άκρων της εικόνας ενός αστερία.

Ανίχνευση άκρων

Εικ. 1.1 Ανίχνευση άκρων

Γιατί χρειαζόμαστε την ανίχνευση άκρων;

Οι ασυνέχειες στο βάθος, ο προσανατολισμός της επιφάνειας, οι διακυμάνσεις του φωτισμού της σκηνής και οι αλλαγές στις ιδιότητες του υλικού οδηγούν σε ασυνέχειες στη φωτεινότητα της εικόνας. Λαμβάνουμε το σύνολο των καμπυλών που υποδεικνύουν τα όρια των αντικειμένων και τα σημάδια της επιφάνειας, και τις καμπύλες που αντιστοιχούν σε ασυνέχειες στον προσανατολισμό της επιφάνειας.
Έτσι, η εφαρμογή ενός αλγόριθμου ανίχνευσης ακμών σε μια εικόνα μπορεί να μειώσει σημαντικά την ποσότητα των δεδομένων που πρόκειται να υποβληθούν σε επεξεργασία και επομένως μπορεί να φιλτράρει πληροφορίες που μπορεί να θεωρηθούν λιγότερο σχετικές, διατηρώντας παράλληλα τις σημαντικές δομικές ιδιότητες μιας εικόνας.
Όπως μπορείτε να δείτε στο σχήμα 1.1, οι δομικές ιδιότητες μιας εικόνας αποτυπώνονται μέσω της ανίχνευσης ακμών.

Κατανόηση των δημοφιλών αλγορίθμων ανίχνευσης ακμών

Έχοντας συζητήσει τη σημασία των αλγορίθμων ανίχνευσης ακμών, αυτή η ενότητα θα επικεντρωθεί στην κατανόηση ορισμένων από τους δημοφιλείς και ευρέως χρησιμοποιούμενους αλγόριθμους ανίχνευσης ακμών.

Υπάρχουν πολλές προσεγγίσεις για την ανίχνευση ακμών. Ας χωρίσουμε γενικά τις προσεγγίσεις σε:

  • Παραδοσιακή προσέγγιση
  • Προσέγγιση βασισμένη στη βαθιά μάθηση

Στη συμβατική προσέγγιση, έχουμε συζητήσει προσεγγίσεις που βασίζονται σε φίλτρα, όπως τα φίλτρα Sobel και Prewitt στο προηγούμενο άρθρο μας. Τώρα, ας συζητήσουμε έναν από τους πιο δημοφιλείς αλγόριθμους ανίχνευσης ακμών – τον ​​ανιχνευτή άκρων και να τον συγκρίνουμε με τους Sobel και Prewitt.

Canny Edge Detector

Ο αλγόριθμος Canny Edge Detection είναι ένας ευρέως χρησιμοποιούμενος αλγόριθμος ανίχνευσης άκρων στις σημερινές εφαρμογές επεξεργασίας εικόνας. Λειτουργεί σε πολλαπλά στάδια όπως φαίνεται στο σχήμα 1.2. Ο αλγόριθμος ανίχνευσης άκρων Canny παράγει πιο ομαλές, λεπτότερες και καθαρότερες εικόνες από τα φίλτρα Sobel και Prewitt.

Εδώ είναι μια περίληψη του αλγόριθμου ανίχνευσης άκρων-

Η εικόνα εισόδου εξομαλύνεται, το φίλτρο Sobel εφαρμόζεται για την ανίχνευση των άκρων της εικόνας. Στη συνέχεια εφαρμόζουμε μη-μέγιστη καταστολή όπου διατηρούνται τα τοπικά μέγιστα pixel στην κατεύθυνση της κλίσης και τα υπόλοιπα καταστέλλονται. Εφαρμόζουμε κατώφλι για να αφαιρέσουμε pixel κάτω από ένα συγκεκριμένο όριο και διατηρούμε τα pixel πάνω από ένα συγκεκριμένο όριο για να αφαιρέσουμε άκρες που θα μπορούσαν να δημιουργηθούν λόγω θορύβου. Αργότερα εφαρμόζουμε παρακολούθηση υστέρησης για να κάνουμε ένα pixel ισχυρό εάν κάποιο από τα 8 γειτονικά pixel είναι ισχυρό.

Canny Edge Detector

Τώρα, θα συζητήσουμε κάθε βήμα λεπτομερώς.

Υπάρχουν 5 βήματα που εμπλέκονται στον εντοπισμό άκρων Canny, όπως φαίνεται στο σχήμα 1.2 παραπάνω. Θα χρησιμοποιήσουμε την παρακάτω εικόνα για απεικόνιση.

Εξομάλυνση εικόνας

Εξομάλυνση εικόνας

Σε αυτό το βήμα, μετατρέπουμε την εικόνα σε κλίμακα του γκρι καθώς η ανίχνευση άκρων δεν εξαρτάται από τα χρώματα. Στη συνέχεια αφαιρούμε το θόρυβο στην εικόνα με ένα φίλτρο Gaussian καθώς η ανίχνευση άκρων είναι επιρρεπής σε θόρυβο.

Εξομάλυνση εικόνας

Εύρεση διαβαθμίσεων έντασης της εικόνας

Στη συνέχεια εφαρμόζουμε τον πυρήνα Sobel σε οριζόντια και κάθετη κατεύθυνση για να πάρουμε την πρώτη παράγωγο στην οριζόντια κατεύθυνση (GΧ) και κάθετη κατεύθυνση (Γy) στην ομαλοποιημένη εικόνα. Στη συνέχεια υπολογίζουμε την κλίση ακμής (G) και τη γωνία (θ) όπως δίνεται παρακάτω,

Edge_Gradient(G) = √(GΧ2+Gy2)

Γωνία(θ)=ταν-1(ΣΟΛy/ΣΟΛΧ)

Γνωρίζουμε ότι η κατεύθυνση της κλίσης είναι κάθετη στην άκρη. Στρογγυλοποιούμε τη γωνία σε μία από τις τέσσερις γωνίες που αντιπροσωπεύουν κάθετες, οριζόντιες και δύο διαγώνιες κατευθύνσεις.

Μη Μέγιστη Καταστολή

Τώρα αφαιρούμε όλα τα ανεπιθύμητα pixel που μπορεί να μην αποτελούν την άκρη. Για αυτό, κάθε pixel ελέγχεται προς την κατεύθυνση της κλίσης εάν είναι ένα τοπικό μέγιστο στη γειτονιά του. Εάν είναι ένα τοπικό μέγιστο, θεωρείται για το επόμενο στάδιο, διαφορετικά, σκουραίνει με 0. Αυτό θα δώσει μια λεπτή γραμμή στην εικόνα εξόδου.

Διπλό κατώφλι

Τα εικονοστοιχεία λόγω θορύβου και χρωματικής διακύμανσης θα παραμένουν στην εικόνα. Έτσι, για να το αφαιρέσουμε, παίρνουμε δύο κατώφλια από τον χρήστη, lowVal και upperVal. Φιλτράρουμε τα εικονοστοιχεία άκρων με χαμηλή τιμή διαβάθμισης (lowerVal) και διατηρούμε τα εικονοστοιχεία ακμών με υψηλή τιμή διαβάθμισης (upperVal). Οι άκρες με κλίση έντασης μεγαλύτερη από το upperVal είναι βέβαιο ότι θα ακμές, και αυτές κάτω από το lowVal είναι βέβαιο ότι δεν είναι άκρες, επομένως απορρίπτονται. Τα εικονοστοιχεία που έχουν τιμή pixel μικρότερη από το upperVal και μεγαλύτερη από το lowVal θεωρούνται μέρος της άκρης εάν είναι συνδεδεμένο σε μια “σίγουρη άκρη”. Διαφορετικά, απορρίπτονται επίσης.

Διπλό κατώφλι

Edge Tracking από την Hysteresis

Ένα εικονοστοιχείο γίνεται ως ισχυρό εικονοστοιχείο εάν κάποιο από τα 8 εικονοστοιχεία γύρω του είναι ισχυρό (τιμή εικονοστοιχείων = 255), διαφορετικά γίνεται ως 0. Edge Tracking από την Hysteresis

Αυτό είναι λίγο πολύ για το Canny Edge Detection. Όπως μπορείτε να δείτε εδώ, οι άκρες εντοπίζονται από μια εικόνα.

Τώρα, θα εξερευνήσουμε τις προσεγγίσεις που βασίζονται στη βαθιά μάθηση για τον εντοπισμό άκρων. Αλλά γιατί πρέπει να χρησιμοποιήσουμε εξαρχής τους αλγόριθμους ανίχνευσης άκρων που βασίζονται σε Deep Learning; Η ανίχνευση άκρων Canny εστιάζει μόνο σε τοπικές αλλαγές και δεν κατανοεί τη σημασιολογία της εικόνας, δηλαδή το περιεχόμενο. Ως εκ τούτου, προτείνονται αλγόριθμοι βασισμένοι σε Deep Learning για την επίλυση αυτών των προβλημάτων. Θα το συζητήσουμε αναλυτικά τώρα.

Αλλά προτού βουτήξουμε στα μαθηματικά της βαθιάς μάθησης, ας προσπαθήσουμε πρώτα να εφαρμόσουμε τον ανιχνευτή άκρων και το μοντέλο που βασίζεται σε βαθιά μάθηση (HED) στο OpenCV.

Εφαρμογή-Ανίχνευση Canny Edge

Ας εισάγουμε τις απαραίτητες ενότητες

import cv2 from skimage.metrics import mean_squared_error,peak_signal_noise_ratio,structural_similarity
import matplotlib.pyplot as plt

Ο ακόλουθος κώδικας εφαρμόζει έναν έξυπνο ανιχνευτή άκρων σε μια εικόνα αστερίας

img_path="starfish.png"
#Reading the image
image = cv2.imread(img_path)
(H, W) = image.shape[:2]
# convert the image to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# blur the image
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
# Perform the canny operator
canny = cv2.Canny(blurred, 30, 150)

Ας δούμε την έξοδο του ανιχνευτή άκρων

fig,ax =  plt.subplots(1,2,figsize=(18, 18))
ax[0].imshow(gray,cmap='gray')
ax[1].imshow(canny,cmap='gray')
ax[0].axis('off')
ax[1].axis('off')

ανίχνευση άκρων
Στη συνέχεια, ας μεταβούμε στον κώδικα του HED πριν πάμε στα μαθηματικά του.

Υλοποίηση-ΗΕΔ

#This class helps in cropping the specified coordinated in the function
class CropLayer(object):
    def __init__(self, params, blobs):
        # initialize our starting and ending (x, y)-coordinates of
        self.startX = 0
        self.startY = 0
        self.endX = 0
        self.endY = 0
    def getMemoryShapes(self, inputs):
        (inputShape, targetShape) = (inputs[0], inputs[1])
        (batchSize, numChannels) = (inputShape[0], inputShape[1])
        (H, W) = (targetShape[2], targetShape[3])
        # compute the starting and ending crop coordinates
        self.startX = int((inputShape[3] - targetShape[3]) / 2)
        self.startY = int((inputShape[2] - targetShape[2]) / 2)
        self.endX = self.startX + W
        self.endY = self.startY + H
        # return the shape of the volume (we'll perform the actual
        # crop during the forward pass
        return [[batchSize, numChannels, H, W]]
    def forward(self, inputs):
        return [inputs[0][:, :, self.startY:self.endY,self.startX:self.endX]]

Μπορείτε να κάνετε λήψη του deploy.prototxt και του caffemodel από αυτό ρεπο

#The caffemodel contains the model of the architecture and the deploy.prototxt contains the weights
protoPath="deploy.prototxt.txt"
modelPath="hed_pretrained_bsds.caffemodel"
net = cv2.dnn.readNetFromCaffe(protoPath, modelPath)
# register our new layer with the model
cv2.dnn_registerLayer("Crop", CropLayer)

Τώρα διαβάζουμε την εικόνα μας και την περνάμε από τον αλγόριθμο.

#Input image is converted to a blog
blob = cv2.dnn.blobFromImage(image, scalefactor=1.0, size=(W, H),mean=(104.00698793, 116.66876762, 122.67891434),swapRB=False, crop=False)
#We pass the blob into the network and make a forward pass
net.setInput(blob)
hed = net.forward()
hed = cv2.resize(hed[0, 0], (W, H))
hed = (255 * hed).astype("uint8")

Διαβάζουμε την πραγματική μας εικόνα, η οποία αποτελείται από άκρες

test_y_path="edge.png"
test_y = cv2.imread(test_y_path)
#The test image has its third dimesion as 3
#So we are extractin only one dimension
test_y = test_y[:,:,0]

Κανονικοποιούμε τις εικόνες για να μην εκτοξεύεται η τιμή MSE!!

#Normalising all the images
test_y = test_y/255
hed = hed/255
canny = canny/255
gray = gray/255

Τώρα οραματιζόμαστε τα αποτελέσματά μας

fig,ax =  plt.subplots(1,2,figsize=(18, 18))
ax[0].imshow(gray,cmap='gray')
ax[1].imshow(hed,cmap='gray')
ax[0].axis('off')
ax[1].axis('off')

ανίχνευση άκρων
Και τέλος, υπολογίζουμε τις μετρήσεις και συγκρίνουμε τα αποτελέσματά μας

#Calculating metrics between actual test image and the output we got through Canny edge detection
print(mean_squared_error(test_y,canny),peak_signal_noise_ratio(test_y,canny),structural_similarity(test_y,canny))
#Calculating metrics between actual test image and the output we got through HED
print(mean_squared_error(test_y,hed),peak_signal_noise_ratio(test_y,hed),structural_similarity(test_y,hed))

ανίχνευση άκρων

Γιατί το DeepLearning για ανίχνευση άκρων;

Πριν διαβάσετε για το HED, μια ερώτηση που θα είχε εμφανιστεί είναι: Γιατί θέλουμε έναν αλγόριθμο Deep Learning για μια τόσο απλή εργασία ανίχνευσης ακμών; Η απάντηση είναι ότι η ανίχνευση άκρων Canny εστιάζει κυρίως στις τοπικές αλλαγές και όχι στη σημασιολογία της εικόνας, δηλαδή εστιάζει λιγότερο στο περιεχόμενο της εικόνας. Ως εκ τούτου, έχουμε λιγότερο ακριβείς άκρες.

Deep Learning Approach for Edge Detection

Μια τεχνική που ονομάζεται Holistically Nested Edge Detection ή HED είναι ένα σύστημα ανίχνευσης από άκρη σε άκρη βασισμένο στη μάθηση που χρησιμοποιεί ένα περικομμένο συνελικτικό νευρωνικό δίκτυο τύπου VGG για μια εργασία πρόβλεψης εικόνας σε εικόνα. Το HED δημιουργεί τις πλευρικές εξόδους στο νευρωνικό δίκτυο. Όλες οι πλευρικές έξοδοι συγχωνεύονται για να κάνουν την τελική έξοδο. Ας κατανοήσουμε τον αλγόριθμο με πιο λεπτομερή τρόπο.

Deep Learning Approach for Edge Detection

Εικ. 1.3 Ανίχνευση άκρων με χρήση HED

Μια σύντομη επισκόπηση του αλγορίθμου

Υιοθετούμε την αρχιτεκτονική VGGNet αλλά κάνουμε τις ακόλουθες τροποποιήσεις:

(α) Συνδέουμε το πλευρικό στρώμα εξόδου μας στο τελευταίο συνελικτικό στρώμα σε κάθε στάδιο, αντίστοιχα conv1 2, conv2 2, conv3 3, conv4 3, conv5 3.

(β) Κόβουμε το τελευταίο στάδιο του VGGNet, συμπεριλαμβανομένου του 5ου στρώματος συγκέντρωσης και όλων των πλήρως συνδεδεμένων στρωμάτων. Επίσης, τα αποσυνελικτικά επίπεδα εντός δικτύου συνδυάζουν τις εξόδους για διγραμμική παρεμβολή.

Deep Learning Approach for Edge Detection

Εικ. 1.4: HED

Η φάση εκπαίδευσης και δοκιμών του HED καλύπτεται στο τέλος του άρθρου ως το βαρύ μαθηματικά τμήμα του. Θα σας συνιστούσα να ρίξετε μια ματιά σε αυτό για να κατανοήσετε καλύτερα την αρχιτεκτονική του μοντέλου.

HED: Φάση Εκπαίδευσης και Δοκιμών

Τώρα, ας μιλήσουμε για τη φάση εκπαίδευσης και δοκιμής του HED. Όπως ανέφερα στην αρχή του άρθρου, αυτή είναι μια ενότητα βαριά για τα μαθηματικά, οπότε σκεφτείτε αυτήν την προαιρετική εκμάθηση. Συνιστώ ανεπιφύλακτα να το διαβάσετε για να κατανοήσετε πραγματικά την εσωτερική λειτουργία του HED

Εκπαιδευτική Φάση

Ας υποδηλώσουμε τη συλλογή όλων των τυπικών παραμέτρων του επιπέδου δικτύου ως W και το δίκτυο έχει M πλευρικά επίπεδα εξόδου. Κάθε επίπεδο πλευρικής εξόδου συνδέεται επίσης με έναν ταξινομητή, στον οποίο τα αντίστοιχα βάρη συμβολίζονται ως w = (w(1), . . . , w(Μ)))

Εκπαιδευτική Φάση

όπου lπλευρά

υποδηλώνει τη λειτουργία απώλειας επιπέδου εικόνας για πλευρικές εξόδους. Για μια τυπική φυσική εικόνα, η κατανομή εικονοστοιχείων άκρων/χωρίς ακμή είναι πολύ προκατειλημμένη: το 90% της αλήθειας εδάφους είναι μη ακμή. Μια συνάρτηση απώλειας που είναι ευαίσθητη στο κόστος είναι με πρόσθετες παραμέτρους αντιστάθμισης που εισάγονται για μεροληπτική δειγματοληψία. Συγκεκριμένα, ορίζουμε την ακόλουθη συνάρτηση απώλειας διασταυρούμενης εντροπίας ισορροπημένης κατηγορίας που χρησιμοποιείται στην παραπάνω εξίσωση

Εκπαιδευτική Φάση

όπου

Για να αξιοποιήσουμε άμεσα τις προβλέψεις πλευρικής εξόδου, προσθέτουμε ένα στρώμα «σταθμισμένης σύντηξης» στο δίκτυο και (ταυτόχρονα) μαθαίνουμε το βάρος σύντηξης κατά τη διάρκεια της προπόνησης. Η συνάρτηση απώλειας στο στρώμα σύντηξης Lασφάλεια ηλεκτρική γίνεται

Εκπαιδευτική Φάση

όπου Dist είναι η απώλεια διασταυρούμενης εντροπίας. Δίνουμε ολόκληρη την αντικειμενική συνάρτηση ως,

Εκπαιδευτική Φάση

Συνδυάζοντας τα πάντα, ελαχιστοποιούμε την ακόλουθη αντικειμενική συνάρτηση μέσω τυπικής (πίσω διάδοσης) στοχαστικής κλίσης κάθοδος:

Φάση δοκιμής

Κατά τη διάρκεια της δοκιμής, δεδομένης της εικόνας X, λαμβάνουμε προβλέψεις χάρτη ακμών τόσο από τα πλευρικά στρώματα εξόδου όσο και από το στρώμα σταθμισμένης σύντηξης. Η τελική ενοποιημένη έξοδος μπορεί να ληφθεί με τη συγκέντρωση αυτών των παραγόμενων χαρτών ακμών.

Μετρήσεις αξιολόγησης

Τώρα, έχουμε κατανοήσει διαφορετικούς αλγόριθμους ανίχνευσης ακμών – Παραδοσιακές μεθόδους και μεθόδους Deep Learning. Πώς όμως αξιολογούμε την απόδοση των αλγορίθμων ανίχνευσης ακμών ή συγκρίνουμε διαφορετικούς αλγόριθμους ανίχνευσης ακμών;

Αυτό μας φέρνει σε ένα άλλο ενδιαφέρον θέμα στον εντοπισμό άκρων – τις μετρήσεις αξιολόγησης. Θα συζητήσουμε τώρα διαφορετικές μετρήσεις αξιολόγησης για τον εντοπισμό ακμών.

Μέσο τετράγωνο σφάλμα

Το MSE αντιπροσωπεύει τη δύναμη του παραμορφωτικού θορύβου που επηρεάζει την ποιότητα της αναπαράστασης.

Δίνεται από

Μέσο τετράγωνο σφάλμαΕξίσωση κορυφής σήματος προς θόρυβο

Ο λόγος κορυφής σήματος προς θόρυβο (PSNR) είναι μια έκφραση για την αναλογία μεταξύ της μέγιστης δυνατής τιμής (ισχύς) ενός σήματος και της ισχύος του παραμορφωτικού θορύβου που επηρεάζει την ποιότητα της αναπαράστασής του. Δίνεται από

Μέσο τετράγωνο σφάλμαΜετρική δείκτη δομικής ομοιότητας

Η μέτρηση του δείκτη δομικής ομοιότητας εξάγει 3 βασικά χαρακτηριστικά από τη φωτεινότητα, την αντίθεση και τη δομή μιας εικόνας. Δίνεται από,

Μετρική δείκτη δομικής ομοιότητας

Μετρική δείκτη δομικής ομοιότηταςΜετρική δείκτη δομικής ομοιότηταςΜετρική δείκτη δομικής ομοιότητας

Οπου,

μΧ είναι ο μέσος όρος της εικόνας Χ

μy είναι ο μέσος όρος της εικόνας Υ

σ2Χ είναι η διακύμανση του Χ

σ2y είναι η διακύμανση του Υ

σxy είναι η συνδιακύμανση των X και Y

ντο1 = (κ1ΜΕΓΑΛΟ)2 και γ2 = (κ2ΜΕΓΑΛΟ)2

κ1= 0,01 και κ2 = 0,03

L = 2όχι. bit ανά pixel -1

συμπέρασμα

Ήταν λίγο μακροσκελή άρθρο! Αλλά καλύψαμε όλες τις έννοιες του ανιχνευτή άκρων Canny και στη συνέχεια τον κωδικοποιήσαμε χρησιμοποιώντας το OpenCV. Συζητήσαμε τα 5 βήματα που εμπλέκονται στην ανίχνευση άκρων Canny, Γιατί ο ανιχνευτής άκρων Canny είναι καλύτερος από τις προηγούμενες μεθόδους. Αργότερα ρίξαμε μια ματιά στα μαθηματικά που εμπλέκονται στη μέθοδο HED. Έχουμε επίσης συζητήσει ορισμένες μετρήσεις αξιολόγησης για να αξιολογήσουμε πόσο καλά αποδίδει ο αλγόριθμος για την εικόνα. Τώρα μπορούμε να κατανοήσουμε τις έννοιες που εμπλέκονται στην ανίχνευση Countour και στους μετασχηματισμούς γραμμής Hough καθώς είναι χτισμένες πάνω από αυτούς τους αλγόριθμους ανίχνευσης ακμών.

Τα βασικά συμπεράσματα αυτού του άρθρου είναι:

  • Ο ανιχνευτής άκρων Canny παρέχει πιο λείες και λεπτότερες άκρες από τα φίλτρα Sobel και Prewitt
  • Χρειαζόμαστε μια προσέγγιση βαθιάς μάθησης καθώς εστιάζει και στο περιεχόμενο της εικόνας

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button