|
| 1 | +<?php |
| 2 | +use CV\Point; |
| 3 | +use CV\Scalar; |
| 4 | +use CV\Mat; |
| 5 | +use function CV\{ |
| 6 | + getStructuringElement, morphologyEx, imshow, namedWindow, |
| 7 | + createTrackbar, getTrackBarPos, waitKey, floodFill, cvtColor, setMouseCallback, |
| 8 | + threshold, destroyWindow |
| 9 | +}; |
| 10 | +use function CV\imread; |
| 11 | +use const CV\{ |
| 12 | + IMREAD_COLOR, WINDOW_AUTOSIZE, COLOR_BGR2GRAY, CV_8UC1, |
| 13 | + EVENT_LBUTTONDOWN, FLOODFILL_FIXED_RANGE, THRESH_BINARY |
| 14 | +}; |
| 15 | + |
| 16 | +$g_srcImage = null;//定义原始图 |
| 17 | +$g_dstImage = null;//目标图 |
| 18 | +$g_grayImage = null;//灰度图 |
| 19 | +$g_maskImage = null;//掩模图 |
| 20 | +$g_nFillMode = 1;//漫水填充的模式 |
| 21 | +$g_nLowDifference = 20;//负差最大值 |
| 22 | +$g_nUpDifference = 20;//正差最大值 |
| 23 | +$g_nConnectivity = 4;//表示floodFill函数标识符低八位的连通值 |
| 24 | +$g_bIsColor = true;//是否为彩色图的标识符布尔值 |
| 25 | +$g_bUseMask = false;//是否显示掩膜窗口的布尔值 |
| 26 | +$g_nNewMaskVal = 255;//新的重新绘制的像素值 |
| 27 | + |
| 28 | +function showHelpText() |
| 29 | +{ |
| 30 | + //输出一些帮助信息 |
| 31 | + printf("\n\n\t欢迎来到漫水填充示例程序~"); |
| 32 | + printf("\n\n\t本示例根据鼠标选取的点搜索图像中与之颜色相近的点,并用不同颜色标注。"); |
| 33 | + |
| 34 | + printf("\n\n\t按键操作说明: \n\n" |
| 35 | + . "\t\t鼠标点击图中区域- 进行漫水填充操作\n" |
| 36 | + . "\t\t键盘按键【ESC】- 退出程序\n" |
| 37 | + . "\t\t键盘按键【1】- 切换彩色图/灰度图模式\n" |
| 38 | + . "\t\t键盘按键【2】- 显示/隐藏掩膜窗口\n" |
| 39 | + . "\t\t键盘按键【3】- 恢复原始图像\n" |
| 40 | + . "\t\t键盘按键【4】- 使用空范围的漫水填充\n" |
| 41 | + . "\t\t键盘按键【5】- 使用渐变、固定范围的漫水填充\n" |
| 42 | + . "\t\t键盘按键【6】- 使用渐变、浮动范围的漫水填充\n" |
| 43 | + . "\t\t键盘按键【7】- 操作标志符的低八位使用4位的连接模式\n" |
| 44 | + . "\t\t键盘按键【8】- 操作标志符的低八位使用8位的连接模式\n\n"); |
| 45 | +} |
| 46 | + |
| 47 | +$onMouse = function (int $event, int $x, int $y) { |
| 48 | + global $g_nFillMode; |
| 49 | + global $g_nLowDifference; |
| 50 | + global $g_nUpDifference; |
| 51 | + global $g_nConnectivity; |
| 52 | + global $g_nNewMaskVal; |
| 53 | + global $g_bIsColor; |
| 54 | + global $g_dstImage; |
| 55 | + global $g_grayImage; |
| 56 | + global $g_bUseMask; |
| 57 | + global $g_maskImage; |
| 58 | + // 若鼠标左键没有按下,便返回 |
| 59 | + //此句代码的OpenCV2版为: |
| 60 | + //if( event != CV_EVENT_LBUTTONDOWN ) |
| 61 | + //此句代码的OpenCV3版为: |
| 62 | + if ($event != EVENT_LBUTTONDOWN) |
| 63 | + return; |
| 64 | + |
| 65 | + //-------------------【<1>调用floodFill函数之前的参数准备部分】--------------- |
| 66 | + $seed = new Point($x, $y); |
| 67 | + $LowDifference = $g_nFillMode == 0 ? 0 : $g_nLowDifference;//空范围的漫水填充,此值设为0,否则设为全局的g_nLowDifference |
| 68 | + $UpDifference = $g_nFillMode == 0 ? 0 : $g_nUpDifference;//空范围的漫水填充,此值设为0,否则设为全局的g_nUpDifference |
| 69 | + |
| 70 | + //标识符的0~7位为g_nConnectivity,8~15位为g_nNewMaskVal左移8位的值,16~23位为CV_FLOODFILL_FIXED_RANGE或者0。 |
| 71 | + //此句代码的OpenCV2版为: |
| 72 | + //int flags = g_nConnectivity + (g_nNewMaskVal << 8) +(g_nFillMode == 1 ? CV_FLOODFILL_FIXED_RANGE : 0); |
| 73 | + //此句代码的OpenCV3版为: |
| 74 | + $flags = $g_nConnectivity + ($g_nNewMaskVal << 8) + ($g_nFillMode == 1 ? FLOODFILL_FIXED_RANGE : 0); |
| 75 | + |
| 76 | + //随机生成bgr值 |
| 77 | + $b = rand(0, 255);//随机返回一个0~255之间的值 |
| 78 | + $g = rand(0, 255);//随机返回一个0~255之间的值 |
| 79 | + $r = rand(0, 255);//随机返回一个0~255之间的值 |
| 80 | + $rect = null;//定义重绘区域的最小边界矩形区域 |
| 81 | + |
| 82 | + $newVal = $g_bIsColor ? new Scalar($b, $g, $r) : new Scalar($r * 0.299 + $g * 0.587 + $b * 0.114);//在重绘区域像素的新值,若是彩色图模式,取Scalar(b, g, r);若是灰度图模式,取Scalar(r*0.299 + g*0.587 + b*0.114) |
| 83 | + |
| 84 | + $dst = $g_bIsColor ? $g_dstImage : $g_grayImage;//目标图的赋值 |
| 85 | + $area = null; |
| 86 | + |
| 87 | + //--------------------【<2>正式调用floodFill函数】----------------------------- |
| 88 | + if ($g_bUseMask) { |
| 89 | + //此句代码的OpenCV2版为: |
| 90 | + //threshold(g_maskImage, g_maskImage, 1, 128, CV_THRESH_BINARY); |
| 91 | + //此句代码的OpenCV3版为: |
| 92 | + threshold($g_maskImage, $g_maskImage, 1, 128, THRESH_BINARY); |
| 93 | + $area = floodFill($dst, $seed, $newVal, $g_maskImage, $rect, new Scalar($LowDifference, $LowDifference, $LowDifference), |
| 94 | + new Scalar($UpDifference, $UpDifference, $UpDifference), $flags); |
| 95 | + imshow("mask", $g_maskImage); |
| 96 | + } else { |
| 97 | + $area = floodFill($dst, $seed, $newVal, null, $rect, new Scalar($LowDifference, $LowDifference, $LowDifference), |
| 98 | + new Scalar($UpDifference, $UpDifference, $UpDifference), $flags); |
| 99 | + } |
| 100 | + |
| 101 | + imshow("result", $dst); |
| 102 | + print_r($area . " 个像素被重绘\n"); |
| 103 | +}; |
| 104 | + |
| 105 | +function run() |
| 106 | +{ |
| 107 | + showHelpText(); |
| 108 | + global $g_srcImage; |
| 109 | + global $g_dstImage; |
| 110 | + global $g_grayImage; |
| 111 | + global $g_maskImage; |
| 112 | + global $g_nLowDifference; |
| 113 | + global $g_nUpDifference; |
| 114 | + global $onMouse; |
| 115 | + global $g_bIsColor; |
| 116 | + global $g_bUseMask; |
| 117 | + $g_srcImage = imread("floodFill2.jpg", 1); |
| 118 | + if ($g_srcImage->empty()) { |
| 119 | + printf("读取图片错误~! \n"); |
| 120 | + return false; |
| 121 | + } |
| 122 | + |
| 123 | + $g_srcImage->copyTo($g_dstImage);//拷贝源图到目标图 |
| 124 | + $g_grayImage = cvtColor($g_srcImage, COLOR_BGR2GRAY);//转换三通道的image0到灰度图 |
| 125 | + $g_maskImage = new Mat($g_srcImage->rows + 2, $g_srcImage->cols + 2, CV_8UC1);//利用image0的尺寸来初始化掩膜mask |
| 126 | + |
| 127 | + namedWindow("result", WINDOW_AUTOSIZE); |
| 128 | + //创建Trackbar |
| 129 | + createTrackbar("Maximum of negative difference", "result", $g_nLowDifference, 255); |
| 130 | + |
| 131 | + createTrackbar("Maximum positive difference", "result", $g_nUpDifference, 255); |
| 132 | + setMouseCallback("result", $onMouse); |
| 133 | + //循环轮询按键 |
| 134 | + while (true) { |
| 135 | + //先显示效果图 |
| 136 | + imshow("result", $g_bIsColor ? $g_dstImage : $g_grayImage); |
| 137 | + |
| 138 | + //获取键盘按键 |
| 139 | + $key = waitKey(0); |
| 140 | + //判断ESC是否按下,若按下便退出 |
| 141 | + if (($key & 255) == 27) { |
| 142 | + printf("程序退出...........\n"); |
| 143 | + break; |
| 144 | + } |
| 145 | + if ($key == -1) { |
| 146 | + continue; |
| 147 | + } |
| 148 | + $key = chr($key); |
| 149 | + //根据按键的不同,进行各种操作 |
| 150 | + switch ($key) { |
| 151 | + //如果键盘“1”被按下,效果图在在灰度图,彩色图之间互换 |
| 152 | + case '1': |
| 153 | + if ($g_bIsColor)//若原来为彩色,转为灰度图,并且将掩膜mask所有元素设置为0 |
| 154 | + { |
| 155 | + printf("键盘“1”被按下,切换彩色/灰度模式,当前操作为将【彩色模式】切换为【灰度模式】\n"); |
| 156 | + $g_grayImage = cvtColor($g_srcImage, COLOR_BGR2GRAY); |
| 157 | + $g_maskImage->setTo(new Scalar(0, 0, 0, 0)); //将mask所有元素设置为0 |
| 158 | + $g_bIsColor = false; //将标识符置为false,表示当前图像不为彩色,而是灰度 |
| 159 | + } else//若原来为灰度图,便将原来的彩图image0再次拷贝给image,并且将掩膜mask所有元素设置为0 |
| 160 | + { |
| 161 | + printf("键盘“1”被按下,切换彩色/灰度模式,当前操作为将【彩色模式】切换为【灰度模式】\n"); |
| 162 | + $g_srcImage->copyTo($g_dstImage); |
| 163 | + $g_maskImage->setTo(new Scalar(0, 0, 0, 0)); |
| 164 | + $g_bIsColor = true;//将标识符置为true,表示当前图像模式为彩色 |
| 165 | + } |
| 166 | + break; |
| 167 | + //如果键盘按键“2”被按下,显示/隐藏掩膜窗口 |
| 168 | + case '2': |
| 169 | + if ($g_bUseMask) { |
| 170 | + destroyWindow("mask"); |
| 171 | + $g_bUseMask = false; |
| 172 | + } else { |
| 173 | + namedWindow("mask", 0); |
| 174 | + $g_maskImage->setTo(new Scalar(0, 0, 0, 0)); |
| 175 | + imshow("mask", $g_maskImage); |
| 176 | + $g_bUseMask = true; |
| 177 | + } |
| 178 | + break; |
| 179 | + //如果键盘按键“3”被按下,恢复原始图像 |
| 180 | + case '3': |
| 181 | + printf("按键“3”被按下,恢复原始图像\n"); |
| 182 | + $g_srcImage->copyTo($g_dstImage); |
| 183 | + $g_grayImage = cvtColor($g_dstImage, COLOR_BGR2GRAY); |
| 184 | + $g_maskImage->setTo(new Scalar(0, 0, 0, 0)); |
| 185 | + break; |
| 186 | + //如果键盘按键“4”被按下,使用空范围的漫水填充 |
| 187 | + case '4': |
| 188 | + printf("按键“4”被按下,使用空范围的漫水填充\n"); |
| 189 | + $g_nFillMode = 0; |
| 190 | + break; |
| 191 | + //如果键盘按键“5”被按下,使用渐变、固定范围的漫水填充 |
| 192 | + case '5': |
| 193 | + printf("按键“5”被按下,使用渐变、固定范围的漫水填充\n"); |
| 194 | + $g_nFillMode = 1; |
| 195 | + break; |
| 196 | + //如果键盘按键“6”被按下,使用渐变、浮动范围的漫水填充 |
| 197 | + case '6': |
| 198 | + printf("按键“6”被按下,使用渐变、浮动范围的漫水填充\n"); |
| 199 | + $g_nFillMode = 2; |
| 200 | + break; |
| 201 | + //如果键盘按键“7”被按下,操作标志符的低八位使用4位的连接模式 |
| 202 | + case '7': |
| 203 | + printf("按键“7”被按下,操作标志符的低八位使用4位的连接模式\n"); |
| 204 | + $g_nConnectivity = 4; |
| 205 | + break; |
| 206 | + //如果键盘按键“8”被按下,操作标志符的低八位使用8位的连接模式 |
| 207 | + case '8': |
| 208 | + printf("按键“8”被按下,操作标志符的低八位使用8位的连接模式\n"); |
| 209 | + $g_nConnectivity = 8; |
| 210 | + break; |
| 211 | + } |
| 212 | + } |
| 213 | + return true; |
| 214 | + |
| 215 | +} |
| 216 | + |
| 217 | +run(); |
0 commit comments