tankian202

Untitled

Dec 4th, 2023 (edited)
123
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 15.29 KB | None | 0 0
  1.  
  2. // Helper function to get color at a specific pixel (x, y)
  3. void getColorLab10(Mat im, int x, int y, uchar& blue, uchar& green, uchar& red) {
  4.     blue = im.at<Vec3b>(y, x)[0];
  5.     green = im.at<Vec3b>(y, x)[1];
  6.     red = im.at<Vec3b>(y, x)[2];
  7. }
  8.  
  9. // Helper function to set color at a specific pixel (x, y)
  10. void setColorLab10(Mat im, int x, int y, uchar blue, uchar green, uchar red) {
  11.     im.at<Vec3b>(y, x)[0] = blue;
  12.     im.at<Vec3b>(y, x)[1] = green;
  13.     im.at<Vec3b>(y, x)[2] = red;
  14. }
  15.  
  16. // Helper function to get grayscale value at a specific pixel (x, y)
  17. uchar getGrayLab10(const Mat& im, int x, int y) {
  18.     return im.at<uchar>(y, x);
  19. }
  20.  
  21. // Helper function to set grayscale value at a specific pixel (x, y)
  22. void setGrayLab10(Mat& im, int x, int y, uchar v) {
  23.     im.at<uchar>(y, x) = v;
  24. }
  25.  
  26. // Helper function for quicksort comparison
  27. int compare(const void* p1, const void* p2) {
  28.     return (*(uint*)p1 > *(uint*)p2) ? 1 : -1;
  29. }
  30.  
  31.  
  32. void Watershed() {
  33.     const uchar bits[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
  34.     // a kifelé folyás irányainak x és y komponense
  35.     const int dx[8] = { 1, 1, 0, -1, -1, -1, 0, 1 };
  36.     const int dy[8] = { 0, -1, -1, -1, 0, 1, 1, 1 };
  37.     // betöltjük a szegmentálandó színes képet
  38.     Mat imColor = imread("3.jpg", 1);
  39.     // készítünk belőle egy szürke verziót
  40.     Mat imO(imColor.cols, imColor.rows, CV_8UC1);
  41.     cvtColor(imColor, imO, COLOR_BGR2GRAY);
  42.     imshow("Szines", imColor);
  43.     waitKey();
  44.     imshow("Szurke", imO);
  45.     waitKey();
  46.     // Ez a kép tárolja majd a kiszámított gradiens értéket minden képpontban
  47.     Mat imG = imO.clone();
  48.     // Ez a kép tárolja majd minden képpont szomszédságában található legkisebb gradiens értéket
  49.         Mat imE = imO.clone();
  50.     // Ez a kép tárolja a kifele folyás irányát minden képpontban
  51.     Mat imKi = imO.clone();
  52.     // Ez a kép tárolja a befele folyás irányait (bitenként) minden képpontban
  53.     Mat imBe = imO.clone();
  54.     //
  55.     // A szegmentált kép lesz (vízgyűjtők átlagolt színével)
  56.     Mat imSegm = imColor.clone();
  57.     // A szegmentált kép lesz (vízgyűjtők medián színével)
  58.     Mat imSegmMed = imColor.clone();
  59.     // Bináris kép mely megmutatja, hogy melyik képpontokban állítottuk már be a kifelefolyást
  60.         Mat imMap = imO.clone();
  61.     // Gradiensek számításához használt 16 bites előjeles kódolású kép
  62.     Mat imL(imColor.cols, imColor.rows, CV_16SC1);
  63.     // felbontjuk a színes képet színcsatornáira
  64.     vector<Mat> imColors;
  65.     split(imColor, imColors);
  66.     // A bemeneti kép három színcsatornáját fogjuk itt tárolni, ezekből számoljuk a gradienseket
  67.         Mat imRed = imColors[2];
  68.     Mat imGreen = imColors[1];
  69.     Mat imBlue = imColors[0];
  70.     // Ezen a képen összegezzük a három színcsatorna gradienseit
  71.     Mat imSum = imO.clone();
  72.     imSum.setTo(Scalar(0));
  73.     // kék színcsatorna gradienseit adjuk hozzá az imSum-hoz
  74.     Sobel(imBlue, imL, imL.depth(), 1, 0);
  75.     convertScaleAbs(imL, imE);
  76.     Sobel(imBlue, imL, imL.depth(), 0, 1);
  77.     convertScaleAbs(imL, imG);
  78.     add(imE, imG, imG);
  79.     addWeighted(imSum, 1, imG, 0.33333, 0, imSum);
  80.     // ződ színcsatorna gradienseit adjuk hozzá az imSum-hoz
  81.     Sobel(imGreen, imL, imL.depth(), 1, 0);
  82.     convertScaleAbs(imL, imE);
  83.     Sobel(imGreen, imL, imL.depth(), 0, 1);
  84.     convertScaleAbs(imL, imG);
  85.     add(imE, imG, imG);
  86.     addWeighted(imSum, 1, imG, 0.33333, 0, imSum);
  87.     // vörös színcsatorna gradienseit adjuk hozzá az imSum-hoz
  88.     Sobel(imRed, imL, imL.depth(), 1, 0);
  89.     convertScaleAbs(imL, imE);
  90.     Sobel(imRed, imL, imL.depth(), 0, 1);
  91.     convertScaleAbs(imL, imG);
  92.     add(imE, imG, imG);
  93.     addWeighted(imSum, 1, imG, 0.33333, 0, imG);
  94.     // Az összesített gradiens az imG képbe került
  95.     //Előfeldolgozási lépés, amelyek közül csak egyiket használjuk
  96.     // 1 - gradiensek csonkolása
  97.     //cvCmpS(imG, 32, imE, CV_CMP_LT);
  98.     //cvSub(imG, imG, imG, imE);
  99.     // 2 - a gradiensek kisimítása egy Gauss-féle aluláteresztő szűrővel
  100.     GaussianBlur(imG, imG, Size(9, 9), 0);
  101.     imshow("Gradiens", imG);
  102.     waitKey();
  103.     // Step 0 - inicializálás
  104.     // Erodált gradiensek kiszámítása - a szomszédságban levő legkisebb gradiensek kiszámítása
  105.         erode(imG, imE, getStructuringElement(MORPH_RECT, Size(3, 3)));
  106.     // A szegmentált képeket inicializáljuk egy szürke árnyalattal, ezeket elvileg mind felül fogja írni az algoritmus
  107.         imSegm.setTo(Scalar(50, 50, 50));
  108.     imSegmMed.setTo(Scalar(150, 150, 150));
  109.     // Egyik pixelnél sincs befelé folyás kezdetben
  110.     imBe.setTo(Scalar(0));
  111.     // Valódi kifelé folyási irányok: 0..7, 8 azt jelenti, hogy az adott pixelnél még nincs eldöntve a kifelé folyás iránya
  112.         imKi.setTo(Scalar(8));
  113.     // Kezdetben sehol nincs még eldöntve a kifelé folyás iránya
  114.     imMap.setTo(Scalar(0));
  115.     // Step 1 - keressük meg és kezeljük le az összes képpontot, ahol a gradiens térkép lejtős
  116.         // Bejárjuk a képet (x,y)-nal
  117.         for (int x = 0; x < imBe.cols; ++x) {
  118.             for (int y = 0; y < imBe.rows; ++y) {
  119.                 int fp = getGray(imG, x, y);
  120.                 int q = getGray(imE, x, y);
  121.                 // ahol az erodált gradiens kisebb a lokális gradiensnél, ott lejtős helyen vagyunk
  122.                     if (q < fp) {
  123.                         // megkeressük, hogy melyik irányba a legmeredekebb a lejtő
  124.                         for (uchar irany = 0; irany < 8; ++irany) {
  125.                             // létezik-e a vizsgált koordinátájú szomszéd
  126.                             if (x + dx[irany] >= 0 && x + dx[irany] < imBe.cols && y + dy[irany]
  127.                                 >= 0 &&
  128.                                 y + dy[irany] < imBe.rows) {
  129.                                 int fpv = getGray(imG, x + dx[irany], y + dy[irany]);
  130.                                 // ha az adott irany szerinti szomszéd gradiense annyi mint a minimum gradiens a szomszédságban...
  131.                                     if (fpv == q) {
  132.                                         //...akkor beállítjuk a kifelé folyást az adott szomszéd irányába
  133.                                             setGray(imKi, x, y, irany);
  134.                                         // bejelöljük, hogy az (x,y) képpontban megvan a kifelé folyás iránya
  135.                                             setGray(imMap, x, y, 255);
  136.                                         // kiolvassuk a befelé folyás bitjeit a szomszédban...
  137.                                         uchar volt = getGray(imBe, x + dx[irany], y + dy[irany]);
  138.                                         // megmódosítjuk ...
  139.                                         uchar adunk = bits[irany];
  140.                                         uchar lesz = volt | adunk;
  141.                                         // és visszaírjuk
  142.                                         setGray(imBe, x + dx[irany], y + dy[irany], lesz);
  143.                                         break;
  144.                                     }
  145.                             }
  146.                         }
  147.                     }
  148.             }
  149.         }
  150.     // megmutatjuk egy ablakban a lekezelt képpontok térképét és várunk gombnyomásra
  151.     imshow("Ablak", imMap);
  152.     waitKey();
  153.     // Step 2 - fennsíkon levő pontok lekezelése a gradiens térképen
  154.     // Kell egy FIFO lista amire képpontokat fogunk elhelyeni
  155.     Point* fifo = new Point[imBe.cols * imBe.rows];
  156.     int nextIn = 0;
  157.     int nextOut = 0;
  158.     // Bejárjuk a képet (x,y)-nal
  159.     for (int x = 0; x < imBe.cols; ++x) {
  160.         for (int y = 0; y < imBe.rows; ++y) {
  161.             // olyan képpontot keresünk, ahol már el van döntve a kifelé folyás iránya de van olyan szomszédja,
  162.                 // ahol még nincs eldöntve
  163.                 int fp = getGray(imG, x, y);
  164.             int pout = getGray(imKi, x, y);
  165.             if (pout == 8) continue;
  166.             // találtunk egy olyan képpontot, ahol a kifelé folyás iránya már el van döntve ...
  167.                 int added = 0;
  168.             // ... és vizsgáljuk annak a szomszédjait
  169.             for (uchar irany = 0; irany < 8; ++irany) {
  170.                 if (x + dx[irany] >= 0 && x + dx[irany] < imBe.cols && y + dy[irany] >= 0
  171.                     &&
  172.                     y + dy[irany] < imBe.rows) {
  173.                     int fpv = getGray(imG, x + dx[irany], y + dy[irany]);
  174.                     int pvout = getGray(imKi, x + dx[irany], y + dy[irany]);
  175.                     if (fpv == fp && pvout == 8) {
  176.                         // ha ide jutunk, akkor találtunk olyan szomszédot, ahol még nincs eldöntve a kifelé folyás iránya
  177.                             // az ilyen (x,y) képpontokat felvesszük a FIFO listára
  178.                             if (added == 0) fifo[nextIn++] = Point(x, y);
  179.                         added++;
  180.                     }
  181.                 }
  182.             }
  183.         }
  184.     }
  185.     // amíg ki nem ürül a FIFO lista
  186.     while (nextOut < nextIn) {
  187.         // kiveszünk egy képpontot a listáról
  188.         Point p = fifo[nextOut++];
  189.         int fp = getGray(imG, p.x, p.y);
  190.         // megkeressük az összes olyan szomszédját, ahol még nincs eldöntve a kifolyás iránya
  191.             for (uchar irany = 0; irany < 8; ++irany) {
  192.                 if (p.x + dx[irany] >= 0 && p.x + dx[irany] < imBe.cols && p.y + dy[irany] >=
  193.                     0 &&
  194.                     p.y + dy[irany] < imBe.rows) {
  195.                     int fpv = getGray(imG, p.x + dx[irany], p.y + dy[irany]);
  196.                     int pvout = getGray(imKi, p.x + dx[irany], p.y + dy[irany]);
  197.                     if (fp == fpv && pvout == 8) {
  198.                         // bejelöljük a kifelé folyás irányát a szomszédtól felénk
  199.                         setGray(imKi, p.x + dx[irany], p.y + dy[irany], (irany + 4) % 8);
  200.                         // bejelöljük, hogy a szomszéd képpontban megvan a kifelé folyás
  201.                         //iránya
  202.                             setGray(imMap, p.x + dx[irany], p.y + dy[irany], 255);
  203.                         // bejelöljük a befelé folyás irányát
  204.                         setGray(imBe, p.x, p.y, bits[(irany + 4) % 8] | getGray(imBe, p.x,
  205.                             p.y));
  206.                         // az újonnan bejelölt szomszéd felkerül a listára
  207.                         fifo[nextIn++] = Point(p.x + dx[irany], p.y + dy[irany]);
  208.                     }
  209.                 }
  210.             }
  211.     }
  212.     // megmutatjuk az ablakban a lekezelt képpontok térképét és várunk gombnyomásra
  213.     imshow("Ablak", imMap);
  214.     waitKey();
  215.     // Step 3 - megkeressük a völgyekhez tartozó képpontokat a gradiens térképen
  216.     // Keresünk olyan képpontot, amilyikből még nincs bejelölve a kifelé folyás iránya
  217.     // Az ilyen képpontot kinevezzük lokális minimumnak és megkeressük körülötte azon
  218.     // pontokat, amelyiknek még nincs kifelé folyása, ezekből mind a lokális minimum felé fog folyni a víz
  219.         // Szükségünk van egy veremre
  220.         Point* stack = new Point[imBe.cols * imBe.rows];
  221.     int nrStack = 0;
  222.     // Bejárjuk a képet (x,y)-nal
  223.     for (int x = 0; x < imBe.cols; ++x) {
  224.         for (int y = 0; y < imBe.rows; ++y)
  225.         {
  226.             int fp = getGray(imG, x, y);
  227.             int pout = getGray(imKi, x, y);
  228.             // Amelyik képpontban már megvan a kifelé folyás irányam azzal nem kell foglalkozni
  229.                 if (pout != 8) continue;
  230.             // pout egy lokális minimumnak lesz kinevezve
  231.             // Megkeressük azokat a szomszédokat, amelyeknek még nincs meg a kifelé folyási irányuk
  232.                 for (uchar irany = 0; irany < 8; ++irany) {
  233.                     if (x + dx[irany] >= 0 && x + dx[irany] < imBe.cols && y + dy[irany] >= 0 &&
  234.                         y + dy[irany] < imBe.rows)
  235.                     {
  236.                         int fpv = getGray(imG, x + dx[irany], y + dy[irany]);
  237.                         int pvout = getGray(imKi, x + dx[irany], y + dy[irany]);
  238.                         if (pvout == 8 && fp == fpv)
  239.                         {
  240.                             // itt találtunk olyan szomszédot
  241.                            // bejelöljük a kifelé folyást a lokális minimum felé
  242.                             setGray(imKi, x + dx[irany], y + dy[irany], (irany + 4) % 8);
  243.                             setGray(imMap, x + dx[irany], y + dy[irany], 255);
  244.                             setGray(imBe, x, y, bits[(irany + 4) % 8] | getGray(imBe, x, y));
  245.                             // a szomszéd képpontot betesszük a verembe
  246.                             stack[nrStack++] = Point(x + dx[irany], y + dy[irany]);
  247.                         }
  248.                     }
  249.                 }
  250.             // amíg ki nem ürül a verem
  251.             while (nrStack > 0)
  252.             {
  253.                 // kiveszünk egy képpontot és megnézzük, hogy a szomszédai között van-e olyan, akinek nincs megjelölve a
  254.                     // kifelé folyás iránya
  255.                     Point pv = stack[--nrStack];
  256.                 int fpv = getGray(imG, pv.x, pv.y);
  257.                 int pvout = getGray(imKi, pv.x, pv.y);
  258.                 for (uchar irany = 0; irany < 8; ++irany) {
  259.                     if (pv.x + dx[irany] >= 0 && pv.x + dx[irany] < imBe.cols && pv.y +
  260.                         dy[irany] >= 0 &&
  261.                         pv.y + dy[irany] < imBe.rows) {
  262.                         // itt találtunk létező szomszédot
  263.                         int fpvv = getGray(imG, pv.x + dx[irany], pv.y + dy[irany]);
  264.                         int pvvout = getGray(imKi, pv.x + dx[irany], pv.y + dy[irany]);
  265.                         //if (fpv==fpvv && pvvout==8 && (!(pv.x+dx[pvout]==x &&pv.y + dy[pvout] == y)))
  266.                         if (fpv == fpvv && pvvout == 8 && (!(pv.x + dx[irany] == x &&
  267.                             pv.y + dy[irany] == y))) {
  268.                             // itt találtunk olyan szomszédot
  269.                            // bejelöljük a kifelé folyást pout felé
  270.                             setGray(imMap, pv.x + dx[irany], pv.y + dy[irany], 255);
  271.                             setGray(imKi, pv.x + dx[irany], pv.y + dy[irany], (irany + 4)
  272.                                 % 8);
  273.                             setGray(imBe, pv.x, pv.y, bits[(irany + 4) % 8] |
  274.                                 getGray(imBe, pv.x, pv.y));
  275.                             // a szomszéd képpontot betesszük a verembe
  276.                             stack[nrStack++] = Point(pv.x + dx[irany], pv.y + dy[irany]);
  277.                         }
  278.                     }
  279.                 }
  280.             }
  281.         }
  282.     }
  283.     // megmutatjuk az ablakban a lekezelt képpontok térképét és várunk gombnyomásra
  284.     // itt már csak izolált fekete képpontok lesznek a fehér képen, ezek a lokális minimumok
  285.         imshow("Ablak", imMap);
  286.     waitKey();
  287.     // Step 4
  288.     // feltérképezzük a vízgyűjtő medencéket a lokális minimumokból kiindulva a víz folyásával fordított irányba haladva
  289.         // minden vízgyűjtő medencében kiszámoljuk az átlagos és a medián színt
  290.         // mindkettőből generálunk egy-egy külön kimeneti szegmentált képet
  291.         // ez a puffer a medián számításához kell
  292.         uint* medbuff = new uint[imBe.cols * imBe.rows];
  293.     int label = 0;
  294.     nextIn = 0;
  295.     int spotSum[3];
  296.     // Bejárjuk a képet (x,y)-nal
  297.     for (int x = 0; x < imBe.cols; ++x) for (int y = 0; y < imBe.rows; ++y) {
  298.         // keresünk lokális mimimumot
  299.         int pout = getGray(imKi, x, y);
  300.         if (pout != 8) continue;
  301.         // találtunk lokális mimimumot, betesszük a verembe
  302.         stack[nrStack++] = Point(x, y);
  303.         for (int i = 0; i < 3; ++i) { spotSum[i] = 0; }
  304.         // amíg üres nem lesz a verem
  305.         while (nrStack > 0) {
  306.             // Kiveszünk egy képpontot a veremből és megnézzük, honnan folyik felénk a víz
  307.                 // Ahonnan felénk folyik a víz, azt a képpontot felvesszük az aktuális régióba és
  308.                 // betesszük a verembe is.
  309.                 Point pv = stack[--nrStack];
  310.             fifo[nextIn++] = pv;
  311.             uchar r, g, b;
  312.             getColorLab10(imColor, pv.x, pv.y, r, g, b);
  313.             spotSum[0] += (int)b;
  314.             spotSum[1] += (int)g;
  315.             spotSum[2] += (int)r;
  316.             uint o = (int)r * 0x10000 + (int)g * 0x100 + (int)b;
  317.             o += (uint)(round((float)r * 0.299 +
  318.                 (float)g * 0.587 + (float)b * 0.114) *
  319.                 0x1000000);
  320.             medbuff[nextIn - 1] = o;
  321.             // setGray(imLabel, pv.x, pv.y, label);
  322.             int pvin = getGray(imBe, pv.x, pv.y);
  323.             for (uchar irany = 0; irany < 8; ++irany) {
  324.                 if ((bits[irany] & pvin) > 0) {
  325.                     // setGray(imLabel, pv.x + dx[(irany + 4) % 8], pv.y + dy[(irany + 4) % 8],label);
  326.                     stack[nrStack++] = Point(pv.x + dx[(irany + 4) % 8], pv.y +
  327.                         dy[(irany + 4) % 8]);
  328.                 }
  329.             }
  330.         }
  331.         // a label azt számolja, hogy hány régió van összesen a szegmentált képen
  332.         label++;
  333.         if (nextIn < 2) printf("%d", nextIn);
  334.         for (int i = 0; i < 3; ++i) {
  335.             spotSum[i] = round(spotSum[i] / nextIn);
  336.         }
  337.         // kiszámoljuk a medián színt a quicksort segítségével
  338.         qsort(medbuff, nextIn, sizeof(uint), compare);
  339.         int medR = (medbuff[nextIn / 2] % 0x1000000) / 0x10000;
  340.         int medG = (medbuff[nextIn / 2] % 0x10000) / 0x100;
  341.         int medB = (medbuff[nextIn / 2] % 0x100);
  342.         for (int i = 0; i < nextIn; ++i) //if (getGray(imMask, fifo[i].x, fifo[i].y) >128)
  343.             {
  344.                 // itt festjük ki a régiót az átlagos színnel
  345.                 setColorLab10(imSegm, fifo[i].x, fifo[i].y, (uchar)spotSum[2], (uchar)
  346.                     spotSum[1], (uchar)spotSum[0]);
  347.                 // itt festjük ki a régiót a medián színnel
  348.                 setColorLab10(imSegmMed, fifo[i].x, fifo[i].y, (uchar)medR, (uchar)medG,(uchar)medB);
  349.             }
  350.         nextIn = 0;
  351.     }
  352.     // memória felszabadítás
  353.     free(fifo);
  354.     free(stack);
  355.     free(medbuff);
  356.     // no more steps
  357.     printf("\nRegions: %d \n", label);
  358.     // megmutatjuk egy ablakban a medián színekkel készített képet
  359.     imshow("Median", imSegmMed);
  360.     // megmutatjuk egy masik ablakban az átlagos színekkel készített képet
  361.     imshow("Atlag", imSegm);
  362.     waitKey();
  363. }
Add Comment
Please, Sign In to add comment