BaseFunction.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. #include "stdafx.h"
  2. #include "BaseFunction.h"
  3. #include <opencv2/core/core.hpp>
  4. #include <opencv2/highgui/highgui.hpp>
  5. #include <opencv2/opencv.hpp>
  6. #include "OTSParticle.h"
  7. #include "OTSImageProcessParam.h"
  8. #include <OTSFieldData.h>
  9. #include "OTSMorphology.h"
  10. #include <opencv2/ximgproc/edge_filter.hpp>
  11. using namespace cv;
  12. using namespace std;
  13. using namespace OTSDATA;
  14. /***** get the distance between two point*****/
  15. float getDistance(Point pointO, Point pointA)
  16. {
  17. float distance;
  18. distance = powf((pointO.x - pointA.x), 2) + powf((pointO.y - pointA.y), 2);
  19. distance = sqrtf(distance);
  20. return distance;
  21. }
  22. /***** get the distance betweem a point and a line*****/
  23. //p is the point, A and B are the two points of the line
  24. float getDist_P2L(Point pointP, Point pointA, Point pointB)
  25. {
  26. //get the line equation Ax+By+C=0
  27. int A = 0, B = 0, C = 0;
  28. A = pointA.y - pointB.y;
  29. B = pointB.x - pointA.x;
  30. C = pointA.x * pointB.y - pointA.y * pointB.x;
  31. //put the point into the line distance equation
  32. float distance = 0;
  33. distance = ((float)abs(A * pointP.x + B * pointP.y + C)) / ((float)sqrtf(A * A + B * B));
  34. return distance;
  35. }
  36. int Side(Point P1, Point P2, Point point)
  37. {
  38. /*Point P1 = line.P1;
  39. Point P2 = line.P2;*/
  40. return ((P2.y - P1.y) * point.x + (P1.x - P2.x) * point.y + (P2.x * P1.y - P1.x * P2.y));
  41. }
  42. void FindInnerCircleInContour(vector<Point> contour, Point& center, int& radius)
  43. {
  44. Rect r = boundingRect(contour);
  45. int nL = r.x, nR = r.br().x; //the left and right boundaries of the contour
  46. int nT = r.y, nB = r.br().y; //the top and bottom boundaries of the contour
  47. double dist = 0;
  48. double maxdist = 0;
  49. for (int i = nL; i < nR; i++) //column
  50. {
  51. for (int j = nT; j < nB; j++) //row
  52. {
  53. //calculate the distance between the inside point and the contour
  54. dist = pointPolygonTest(contour, Point(i, j), true);
  55. if (dist > maxdist)
  56. {
  57. //get the point with the maximum distance
  58. maxdist = dist;
  59. center = Point(i, j);
  60. }
  61. }
  62. }
  63. radius = maxdist; //the radius is the maximum distance between the inside point and the contour
  64. }
  65. BOOL GetParticleAverageChord(std::vector<Point> listEdge, double a_PixelSize, double& dPartFTD)
  66. {
  67. // safety check
  68. double nx = 0, ny = 0;
  69. Moments mu;
  70. mu = moments(listEdge, false);
  71. nx = mu.m10 / mu.m00;
  72. ny = mu.m01 / mu.m00;
  73. //circle(cvcopyImg, Point(nx, ny), 1, (255), 1);
  74. Point ptCenter = Point((int)nx, (int)ny);
  75. // coordinate transformation
  76. Point ptPosition;
  77. int radiusNum = 0;
  78. // get ferret diameter
  79. double sumFltDiameter = 0;
  80. int interval;
  81. int edgePointNum = listEdge.size();
  82. if (edgePointNum > 10)
  83. {
  84. interval = edgePointNum / 10;//get one line per 10 degree aproxemately
  85. }
  86. else
  87. {
  88. interval = 1;
  89. }
  90. for (int i = 0; i < edgePointNum; i++)
  91. {
  92. Point pt = listEdge[i];
  93. ptPosition.x = abs(pt.x - ptCenter.x);
  94. ptPosition.y = abs(pt.y - ptCenter.y);
  95. if (i % interval == 0)//calculate one line per 10 point ,so to speed up.don't calculate all the diameter.
  96. {
  97. double r1 = sqrt(pow(ptPosition.x, 2) + pow(ptPosition.y, 2));
  98. sumFltDiameter += r1;
  99. radiusNum += 1;
  100. //line(cvImageData, ptCenter, pt, Scalar(nBlackColor), nThickness, nLineType);
  101. }
  102. }
  103. if (radiusNum == 0)
  104. {
  105. dPartFTD = 0;
  106. }
  107. else
  108. {
  109. dPartFTD = a_PixelSize * sumFltDiameter / radiusNum * 2;
  110. }
  111. //imshow("feret center", cvImageData);
  112. return TRUE;
  113. }
  114. void linearSmooth5(WORD wordIn[], WORD wordOut[], int N = 255)//smooth algorithm
  115. {
  116. double in[256];
  117. double out[256];
  118. double smoothCurveData[256];
  119. for (int i = 0; i < 256; i++)
  120. {
  121. in[i] = (double)wordIn[i];
  122. }
  123. int i;
  124. if (N < 5)
  125. {
  126. for (i = 0; i <= N - 1; i++)
  127. {
  128. out[i] = in[i];
  129. }
  130. }
  131. else
  132. {
  133. out[0] = (3.0 * in[0] + 2.0 * in[1] + in[2] - in[4]) / 5.0;
  134. out[1] = (4.0 * in[0] + 3.0 * in[1] + 2 * in[2] + in[3]) / 10.0;
  135. for (i = 2; i <= N - 3; i++)
  136. {
  137. out[i] = (in[i - 2] + in[i - 1] + in[i] + in[i + 1] + in[i + 2]) / 5.0;
  138. }
  139. out[N - 2] = (4.0 * in[N - 1] + 3.0 * in[N - 2] + 2 * in[N - 3] + in[N - 4]) / 10.0;
  140. out[N - 1] = (3.0 * in[N - 1] + 2.0 * in[N - 2] + in[N - 3] - in[N - 5]) / 5.0;
  141. }
  142. for (int i = 0; i < N; i++)
  143. {
  144. wordOut[i] = (WORD)out[i];
  145. }
  146. }
  147. void BlurImage(CBSEImgPtr inImg)
  148. {
  149. int rows, cols;
  150. cols = inImg->GetWidth();
  151. rows = inImg->GetHeight();
  152. BYTE* pPixel = inImg->GetImageDataPointer();
  153. Mat cvcopyImg = Mat(rows, cols, CV_8UC1, pPixel);
  154. //Mat blurImg;
  155. //medianBlur(cvcopyImg, cvcopyImg, 5);//get rid of the noise point.
  156. //cv::bilateralFilter
  157. cv::GaussianBlur(cvcopyImg, cvcopyImg, Size(5, 5), 2);
  158. //inImg->SetImageData(cvcopyImg.data, width, height);
  159. /*outImg = inImg;*/
  160. }
  161. Mat GetMatDataFromBseImg(CBSEImgPtr inImg)
  162. {
  163. int rows, cols;
  164. cols = inImg->GetWidth();
  165. rows = inImg->GetHeight();
  166. BYTE* pPixel = inImg->GetImageDataPointer();
  167. Mat cvcopyImg = Mat(rows, cols, CV_8UC1, pPixel);
  168. return cvcopyImg;
  169. }
  170. CBSEImgPtr GetBSEImgFromMat(Mat inImg)
  171. {
  172. CBSEImgPtr bse = CBSEImgPtr(new CBSEImg(CRect(0, 0, inImg.cols, inImg.rows)));
  173. BYTE* pPixel = inImg.data;
  174. bse->SetImageData(pPixel, inImg.cols, inImg.rows);
  175. return bse;
  176. }
  177. /***********************************************************
  178. the enhancement algorithm is based on the proportion of each gray value in the entire image
  179. Then, as a gain factor, the proportion of all gray values less than the current gray value in the total pixels
  180. Each pixel point is adjusted. Since the gain factor of each value is the sum of the proportions of all values less than it.
  181. So the image after enhancement is brighter and darker.
  182. ************************************************************/
  183. void ImageStretchByHistogram(const Mat& src, Mat& dst)
  184. {
  185. //judge the size of the two images
  186. if (!(src.size().width == dst.size().width))
  187. {
  188. cout << "error" << endl;
  189. return;
  190. }
  191. double p[256], p1[256], num[256];
  192. memset(p, 0, sizeof(p));
  193. memset(p1, 0, sizeof(p1));
  194. memset(num, 0, sizeof(num));
  195. int height = src.size().height;
  196. int width = src.size().width;
  197. long wMulh = height * width;
  198. //statistics of each gray value in the image
  199. for (int x = 0; x < width; x++)
  200. {
  201. for (int y = 0; y < height; y++)
  202. {
  203. uchar v = src.at<uchar>(y, x);
  204. num[v]++;
  205. }
  206. }
  207. //using the number of each gray value to calculate the proportion of each gray value in the total pixels
  208. for (int i = 0; i < 256; i++)
  209. {
  210. p[i] = num[i] / wMulh;
  211. }
  212. //calculate the cumulative distribution function
  213. //p1[i]=sum(p[j]); j<=i;
  214. for (int i = 0; i < 256; i++)
  215. {
  216. for (int k = 0; k <= i; k++)
  217. p1[i] += p[k];
  218. }
  219. //using the cumulative distribution function to adjust the pixel value
  220. for (int y = 0; y < height; y++)
  221. {
  222. for (int x = 0; x < width; x++) {
  223. uchar v = src.at<uchar>(y, x);
  224. dst.at<uchar>(y, x) = p1[v] * 255 + 0.5;
  225. }
  226. }
  227. return;
  228. }
  229. //adjust the contrast of the image
  230. Mat AdjustContrastY(const Mat& img)
  231. {
  232. Mat out = Mat::zeros(img.size(), CV_8UC1);
  233. Mat workImg = img.clone();
  234. //enhance the image
  235. ImageStretchByHistogram(workImg, out);
  236. return Mat(out);
  237. }
  238. void CVRemoveBG(const cv::Mat& img, cv::Mat& dst,int bgstart,int bgend/*, long& nNumParticle*/)
  239. {
  240. int min_gray = bgstart;
  241. int max_gray = bgend;
  242. if (img.empty())
  243. {
  244. std::cout << "empty image";
  245. return;
  246. }
  247. Mat image = img.clone();
  248. if (image.channels() != 1)
  249. {
  250. cv::cvtColor(image, image, cv::COLOR_BGR2GRAY);
  251. }
  252. //lut: lookup table,exclude the gray value less than min_gray and greater than max_gray
  253. uchar lutvalues[256];
  254. for (int i = 0; i < 256; i++)
  255. {
  256. if (i <= min_gray || i >= max_gray)
  257. {
  258. lutvalues[i] = 255;
  259. /*nNumParticle++;*/
  260. }
  261. else
  262. {
  263. lutvalues[i] = 0;
  264. }
  265. }
  266. cv::Mat lutpara(1, 256, CV_8UC1, lutvalues);
  267. cv::LUT(image, lutpara, image);
  268. cv::Mat out_fill0, out_fill;
  269. //open calculation
  270. cv::morphologyEx(image, out_fill0, cv::MorphTypes::MORPH_OPEN, cv::getStructuringElement(0, cv::Size(5, 1)), cv::Point(-1, -1), 1);
  271. cv::morphologyEx(image, out_fill, cv::MorphTypes::MORPH_OPEN, cv::getStructuringElement(0, cv::Size(1, 5)), cv::Point(-1, -1), 1);
  272. out_fill = out_fill + out_fill0;
  273. //close calculation
  274. cv::morphologyEx(out_fill, out_fill, cv::MorphTypes::MORPH_CLOSE, cv::getStructuringElement(0, cv::Size(3, 3)), cv::Point(-1, -1), 1);
  275. //binary thresholding
  276. cv::threshold(out_fill, out_fill, 1, 255, cv::ThresholdTypes::THRESH_BINARY);
  277. dst = out_fill.clone();
  278. }
  279. void RemoveBG_old(const cv::Mat& img, cv::Mat& dst, int nBGStart, int nBGEnd,long& nNumParticle)
  280. {
  281. int w, h;
  282. w = img.cols;
  283. h = img.rows;
  284. BYTE* pSrcImg = img.data;
  285. BYTE* pPixel = new BYTE[w * h];
  286. BYTE* pTempImg = new BYTE[w * h];
  287. for (unsigned int i = 0; i < w*h; i++)
  288. {
  289. if (pSrcImg[i] < nBGStart || pSrcImg[i] > nBGEnd)
  290. {
  291. pPixel[i] = 255;
  292. nNumParticle++;
  293. }
  294. else
  295. {
  296. pPixel[i] = 0;
  297. }
  298. }
  299. int errodDilateParam =5;
  300. if (errodDilateParam > 0)
  301. {
  302. BErode3(pPixel, pTempImg, errodDilateParam, h, w);
  303. BDilate3(pTempImg, pPixel, errodDilateParam, h, w);
  304. }
  305. dst.data = pPixel;
  306. delete[] pTempImg;
  307. }
  308. void AutoRemove_background_OTS(const cv::Mat& img, cv::Mat& dst, int black_thing, int min_size, int min_gray)
  309. {
  310. if (img.empty())
  311. {
  312. return;
  313. }
  314. Mat image = img.clone();
  315. if (image.channels() != 1)
  316. {
  317. cv::cvtColor(image, image, cv::COLOR_BGR2GRAY);
  318. }
  319. cv::Scalar mean, std;
  320. cv::meanStdDev(image, mean, std);
  321. auto a = mean[0];
  322. auto d = std[0];
  323. bool direct_binary = false;
  324. if (a > 240)//bright background, dark particle;direct binary process ;particular case
  325. {
  326. direct_binary = true;
  327. }
  328. bool both_black_bright = false;
  329. auto parame0 = black_thing;
  330. auto parame1 = min_size;
  331. auto parame2 = min_gray;
  332. if (parame0 == 2)
  333. {
  334. both_black_bright = true;
  335. }
  336. //adaptive manifold filter
  337. cv::Ptr<cv::ximgproc::AdaptiveManifoldFilter> pAdaptiveManifoldFilter
  338. = cv::ximgproc::createAMFilter(3.0, 0.1, true);
  339. cv::Mat temp1, dst_adapt;
  340. cv::Mat out_thresh;//get the binary image of the extracted particle
  341. if (direct_binary)
  342. {
  343. int min = 30;
  344. int thre = a - d - 50;
  345. if ((a - d - 50) < 30)
  346. {
  347. thre = min;
  348. }
  349. cv::threshold(image, out_thresh, thre, 255, cv::ThresholdTypes::THRESH_BINARY_INV);
  350. }
  351. else
  352. {
  353. cv::GaussianBlur(image, temp1, cv::Size(3, 3), 1.0, 1.0);
  354. pAdaptiveManifoldFilter->filter(temp1, dst_adapt, image);
  355. //dst_adapt = image;
  356. cv::ThresholdTypes img_ThresholdTypes = cv::ThresholdTypes::THRESH_BINARY_INV;
  357. cv::Mat image_Negate;
  358. if (both_black_bright)
  359. {
  360. //get the dark object
  361. cv::Mat black_t;
  362. int min_gray = 0;
  363. float segma_b = 1.5;
  364. int max_gray = int(a - d * segma_b);
  365. max_gray = std::min(max_gray, 255);
  366. uchar lutvalues[256];
  367. for (int i = 0; i < 256; i++)
  368. {
  369. if (i >= min_gray && i <= max_gray)
  370. {
  371. lutvalues[i] = 255;
  372. }
  373. else
  374. {
  375. lutvalues[i] = 0;
  376. }
  377. }
  378. cv::Mat lutpara(1, 256, CV_8UC1, lutvalues);
  379. cv::LUT(dst_adapt, lutpara, black_t);
  380. //get the bright object
  381. cv::Mat bright_t;
  382. int min_gray_bright = int(a + d * segma_b);
  383. int max_gray_bright = 255;
  384. min_gray_bright = std::max(min_gray_bright, 120);
  385. uchar lutvalues1[256];
  386. for (int i = 0; i < 256; i++)
  387. {
  388. if (i >= min_gray_bright && i <= max_gray_bright)
  389. {
  390. lutvalues1[i] = 255;
  391. }
  392. else
  393. {
  394. lutvalues1[i] = 0;
  395. }
  396. }
  397. cv::Mat lutpara1(1, 256, CV_8UC1, lutvalues1);
  398. cv::LUT(dst_adapt, lutpara1, bright_t);
  399. out_thresh = black_t + bright_t;
  400. //cv::threshold(out_thresh, out_thresh, 1, 255, cv::ThresholdTypes::THRESH_BINARY);
  401. }
  402. else
  403. {
  404. //convert the image to its negative image
  405. if (!direct_binary && (parame0 == 0))//dark particle,bright background
  406. {
  407. image_Negate = image;
  408. }
  409. else
  410. {
  411. dst_adapt = ~dst_adapt;
  412. image_Negate = ~image;
  413. }
  414. //triangle thresholding
  415. auto result_THRESH_TRIANGLE = cv::threshold(dst_adapt, out_thresh, 100, 255, cv::ThresholdTypes::THRESH_TRIANGLE | img_ThresholdTypes);
  416. cv::Mat extractedImage;
  417. cv::bitwise_and(image_Negate, image_Negate, extractedImage, out_thresh = out_thresh > 0); // 使用mask > 0将mask转换为二值图像
  418. //calculate the mean and std of the extracted image
  419. cv::Scalar mean1, std1;
  420. cv::meanStdDev(extractedImage, mean1, std1, out_thresh);
  421. auto mean0 = mean1[0];
  422. auto std0 = std1[0];
  423. // binaryImage;remove the pixels greater than the threshold
  424. cv::Mat binaryImage = cv::Mat::zeros(image_Negate.size(), image_Negate.type());
  425. //the filter coefficient
  426. int segma = 4;
  427. float filter_gray = (mean0 + std0 / segma);
  428. //filter_gray = result_THRESH_TRIANGLE;
  429. for (int y = 0; y < extractedImage.rows; ++y) {
  430. for (int x = 0; x < extractedImage.cols; ++x) {
  431. if (extractedImage.at<uchar>(y, x) >= 1 && extractedImage.at<uchar>(y, x) <= (int)(filter_gray)) {
  432. binaryImage.at<uchar>(y, x) = 255; //set to white(255)
  433. }
  434. }
  435. }
  436. //get the less than parame2(default 30)area
  437. cv::Mat thing_area;
  438. cv::threshold(image_Negate, thing_area, parame2, 255, img_ThresholdTypes);
  439. //out_thresh = binaryImage ;
  440. out_thresh = binaryImage + thing_area;
  441. }
  442. }
  443. cv::Mat img_draw = cv::Mat::zeros(image.size(), CV_8UC3);
  444. //get the connected components
  445. //random color
  446. cv::RNG rng(10086);
  447. cv::Mat labels, stats, controids;
  448. int number = cv::connectedComponentsWithStats(out_thresh, labels, stats, controids, 8, CV_16U);
  449. std::vector<cv::Vec3b> colors;
  450. vector<int> draw_indexs;
  451. for (int i = 0; i < number; i++)
  452. {
  453. cv::Vec3b color = cv::Vec3b(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));
  454. colors.emplace_back(color);
  455. auto area = stats.at<int>(i, CC_STAT_AREA);
  456. if (area < parame1)
  457. {
  458. continue;
  459. }
  460. draw_indexs.push_back(i);
  461. }
  462. //color the connected components
  463. int w = img_draw.cols;
  464. int h = img_draw.rows;
  465. cv::Vec3b color = cv::Vec3b(0, 0, 255);
  466. for (int row = 0; row < h; row++)
  467. {
  468. for (int col = 0; col < w; col++)
  469. {
  470. int label = labels.at<uint16_t>(row, col);
  471. if (label == 0)
  472. {
  473. continue;
  474. }
  475. auto it = std::find(draw_indexs.begin(), draw_indexs.end(), label);
  476. if (it != draw_indexs.end())
  477. {
  478. img_draw.at<Vec3b>(row, col) = color;
  479. }
  480. }
  481. }
  482. //color the particle on the original image
  483. //cv::Mat img_blend;
  484. //double alpha = 0.7; // set the weight of img1
  485. //double beta = 1 - alpha; // calculate the weight of img2
  486. //cv::cvtColor(image, image, cv::COLOR_GRAY2BGR);
  487. //cv::addWeighted(image, alpha, img_draw, beta, 0.0, img_blend);
  488. //dst = img_blend.clone();
  489. //binary image
  490. vector<cv::Mat> outs;
  491. cv::split(img_draw, outs);
  492. dst = outs[2].clone();
  493. }