Title: Blue Apple - Isolation and removal of apple core housings in color images Authors: Jonas Credner, Maryam Fadami, Peter Rehrmann, Thomas Rath Year:2022 Keywords: Image pre-processing, colour selection, identification biological objects, binarisation, starch detection apples, Halcon Abstract: Image processing of color images often requires pre-processing that reduces the image to regions of interest and enables or simplifies downstream image processing. The code shown here was used in conjunction with Blue Apple software to perform classification of apples to a starch index. The unprocessed images showed two apple halves, one dyed with iodine solution and one untreated half of the same apple on a black background. Based on the color image of the untreated apple, the image was binarized and the apple halves were separated from the background. The region of the core housing was then identified and removed from the image file. The image files pre-treated in this way could be processed by the Blue Apple software. For this we use the image processing library Halcon (Halcon 2022). Cite as: J. Credner, M. Fadami, P. Rehrmann, T. Rath (2022): Blue Apple - Isolation and removal of apple core housings in color images. BLab Code No. 20222, http://www.blab-osnabrueck.de/blue-apple2.txt Literature: Halcon (2022): Halcon - Die Leistungsstarke Software fuer Ihre Bildverarbeitungsanwendung. MVTec Software GmbH, Munich, Germany Affiliation: J. Credner, M. Fadami, P. Rehrmann, T. Rath Biosystem Engineering Laboratory (BLab), Osnabrueck University of Applied sciences email: j.credner@hs-osnabrueck.de, p.rehrmann@hs-osnabrueck.de, t.rath@hs-osnabrueck.de ############################################################################## # File generated by HDevelop for text file Version 13.0.3 ############################################################################## # Main procedure FirstImageRotated := false list_files ('C:/Users/blab1/Desktop/Apfel Staerke Test/Sorten', 'files', ApfelBilder) tuple_length (ApfelBilder, ApfelBilderAnzahl) for a := 0 to ApfelBilderAnzahl - 1 by 1 * *Apfelbild einlesen read_image (AepfelImage, ApfelBilder[a]) repeat if (FirstImageRotated = true) rotate_image (AepfelImage, AepfelImage, 90, 'constant') endif * *Apfelbild in zwei Teile auftrennen --> Linker Apfel und rechter Apfel get_image_size (AepfelImage, Width, Height) gen_rectangle1 (RectangleLinkeSeite, 0, 0, Height, Width/2) reduce_domain (AepfelImage, RectangleLinkeSeite, LinkerApfel) gen_rectangle1 (RectangleRechteSeite, 0, Width/2, Height, Width) reduce_domain (AepfelImage, RectangleRechteSeite, RechterApfel) * *Linken Apfel vom Hintergrund trennen decompose3 (LinkerApfel, LinkerApfelR, LinkerApfelG, LinkerApfelB) trans_from_rgb (LinkerApfelR, LinkerApfelG, LinkerApfelB, ImageResult1, ImageResult2, ImageResult3, 'hsi') rgb1_to_gray (LinkerApfel, LinkerApfelGrau) binary_threshold (LinkerApfelGrau, RegionLinkeSeite, 'max_separability', 'light', UsedThreshold) connection (RegionLinkeSeite, ConnectedRegionsLinkeSeite) select_shape_std (ConnectedRegionsLinkeSeite, RegionNurApfelLinkeSeite, 'max_area', 70) fill_up (RegionNurApfelLinkeSeite, RegionNurApfelLinkeSeiteFillUp) circularity (RegionNurApfelLinkeSeiteFillUp, Circularity) FirstImageRotated := true until (Circularity >= 0.84) FirstImageRotated := false * *Konturen des linken Apfels in Modell ueberfuehren gen_contour_region_xld (RegionNurApfelLinkeSeiteFillUp, LinkerApfelContours, 'border') create_aniso_shape_model_xld (LinkerApfelContours, 'auto', -3.14, 6.29, 0.0175, 1, 1, 'auto', 1, 1, 'auto', 'auto', 'ignore_local_polarity', 5, ModelIDLinkerApfel) get_shape_model_contours (LinkerApfelModelContours, ModelIDLinkerApfel, 1) * *Konturen des linken Apfels im Grauwertbild des rechten Apfels suchen und transformieren rgb1_to_gray (RechterApfel, RechterApfelGrau) find_aniso_shape_model (RechterApfelGrau, ModelIDLinkerApfel, -3.14, 6.29, 1, 1, 1, 1, 0.1, 1, 0.5, 'least_squares', 0, 0, Row, Column, Angle, ScaleR, ScaleC, Score) hom_mat2d_identity (HomMat2DLinkerApfel) hom_mat2d_scale (HomMat2DLinkerApfel, ScaleR, ScaleC, 0, 0, HomMat2D) hom_mat2d_rotate (HomMat2DLinkerApfel, Angle, 0, 0, HomMat2DLinkerApfel) hom_mat2d_translate (HomMat2DLinkerApfel, Row, Column, HomMat2DLinkerApfel) affine_trans_contour_xld (LinkerApfelModelContours, RechterApfelContoursTrans, HomMat2DLinkerApfel) gen_region_contour_xld (RechterApfelContoursTrans, RegionRechterApfelContoursFilled, 'filled') gen_region_contour_xld (LinkerApfelModelContours, RegionLinkerApfelContoursFilled, 'filled') * *Faechen der gefundenen Aepfel berechnen area_center (RegionLinkerApfelContoursFilled, AreaLinkerApfel, RowLinkerApfel, ColumnLinkerApfel) area_center (RegionRechterApfelContoursFilled, AreaRechterApfel, RowRechterApfel, ColumnRechterApfel) * * smallest_circle (RegionNurApfelLinkeSeiteFillUp, LinkerApfelKleinterKreisRow, LinkerApfelKleinterKreisRowColumn, LinkerApfelKleinterKreisRowRadius) gen_circle (LinkerApfelHalberKleinterKreis, LinkerApfelKleinterKreisRow, LinkerApfelKleinterKreisRowColumn, LinkerApfelKleinterKreisRowRadius/2) reduce_domain (LinkerApfel, LinkerApfelHalberKleinterKreis, LinkerApfelKerngehause) decompose3 (LinkerApfelKerngehause, LinkerApfelKerngehauseR, LinkerApfelKerngehauseG, LinkerApfelKerngehauseB) trans_from_rgb (LinkerApfelKerngehauseR, LinkerApfelKerngehauseG, LinkerApfelKerngehauseB, LinkerApfelKerngehauseImageResult1, LinkerApfelKerngehauseImageResult2, LinkerApfelKerngehauseImageResult3, 'i1i2i3') rgb1_to_gray (LinkerApfelKerngehause, LinkerApfelKerngehauseGrau) binary_threshold (LinkerApfelKerngehauseGrau, RegionLinkesKerngehause, 'max_separability', 'dark', UsedThreshold1) connection (RegionLinkesKerngehause, ConnectedRegionsLinkesKerngehause) select_shape_std (ConnectedRegionsLinkesKerngehause, SelectedRegionsLinkesKerngehause, 'max_area', 70) fill_up (SelectedRegionsLinkesKerngehause, LinkesKerngehauseRegionFillUp) smallest_circle (RegionRechterApfelContoursFilled, RechterApfelKleinsterKreisRow, RechterApfelKleinsterKreisColumn, RechterApfelKleinsterKreisRadius) gen_circle (RechterApfelHalberKleinsterKreis, RechterApfelKleinsterKreisRow, RechterApfelKleinsterKreisColumn, RechterApfelKleinsterKreisRadius/2) reduce_domain (RechterApfel, RechterApfelHalberKleinsterKreis, NurRechterApfelKerngehause) decompose3 (NurRechterApfelKerngehause, NurRechterApfelKerngehauseR, NurRechterApfelKerngehauseG, NurRechterApfelKerngehauseB) trans_from_rgb (NurRechterApfelKerngehauseR, NurRechterApfelKerngehauseG, NurRechterApfelKerngehauseB, NurRechterApfelKerngehauseImageResult1, NurRechterApfelKerngehauseImageResult2, NurRechterApfelKerngehauseImageResult3, 'cielchuv') * *Linkes Kerngeh„use Kontur erstellen und im rechten Apfel finden gen_contour_region_xld (LinkesKerngehauseRegionFillUp, LinkerApfelKerngehauseContours, 'border') create_aniso_shape_model_xld (LinkerApfelKerngehauseContours, 'auto', -3.14, 6.29, 0.0175, 1, 1, 'auto', 1, 1, 'auto', 'auto', 'ignore_local_polarity', 5, LinkesKerngehauseModelID) get_shape_model_contours (LinkerApfelKerngehauseModelContours, LinkesKerngehauseModelID, 1) rgb1_to_gray (NurRechterApfelKerngehause, NurRechterApfelKerngehauseGrau) find_aniso_shape_model (NurRechterApfelKerngehauseGrau, LinkesKerngehauseModelID, -3.14, 6.29, 1, 1, 1, 1, 0.1, 1, 0.5, 'least_squares', 0, 0, Row, Column, Angle, ScaleR, ScaleC, Score) hom_mat2d_identity (HomMat2DKerngehause) hom_mat2d_scale (HomMat2D, ScaleR, ScaleC, 0, 0, HomMat2D) hom_mat2d_rotate (HomMat2DKerngehause, Angle, 0, 0, HomMat2DKerngehause) hom_mat2d_translate (HomMat2DKerngehause, Row, Column, HomMat2DKerngehause) affine_trans_contour_xld (LinkerApfelKerngehauseModelContours, RechterApfelKerngehauseContoursTrans, HomMat2DKerngehause) gen_region_contour_xld (RechterApfelKerngehauseContoursTrans, RechterApfelKerngehauseRegionFilled, 'filled') gen_region_contour_xld (LinkerApfelKerngehauseModelContours, LinkerApfelKerngehauseRegionFilled, 'filled') smallest_circle (LinkesKerngehauseRegionFillUp, Row1, Column1, Radius) smallest_circle (RechterApfelKerngehauseRegionFilled, Row2, Column2, Radius1) gen_circle (CircleLinks, Row1, Column1, Radius) gen_circle (CircleRechts, Row2, Column2, Radius1) gen_circle (CircleClosing, Row2, Column2, Radius1 * 0.1) closing (RechterApfelKerngehauseRegionFilled, CircleClosing, RegionClosing) dilation_circle (RechterApfelKerngehauseRegionFilled, RegionDilationRechts1, Radius * 0.1) dilation_circle (RegionDilationRechts1, RegionDilationRechts2, Radius * 0.1) dilation_circle (LinkesKerngehauseRegionFillUp, RegionDilationLinks1, Radius * 0.1) dilation_circle (RegionDilationLinks1, RegionDilationLinks2, Radius * 0.1) difference (RegionNurApfelLinkeSeiteFillUp, RegionDilationLinks2, RegionDifferenceLinks) difference (RegionRechterApfelContoursFilled, RegionDilationRechts2, RegionDifferenceRechts) reduce_domain (AepfelImage, RegionDifferenceLinks, LinkerApfelBildOhneKerngehause) reduce_domain (AepfelImage, RegionDifferenceRechts, RechterApfelBildOhneKerngehause) Separator := ['\\'] tuple_split (ApfelBilder[a], Separator, SubstringsApfel) tuple_length (SubstringsApfel, SubstringsApfelLength) write_image (LinkerApfelBildOhneKerngehause, 'png', 0, 'C:/Users/blab1/Desktop/Apfel St„rke Test/EinzelneAepfel' + '/' + 'ApfelOhneIod_' +SubstringsApfel[SubstringsApfelLength-1]) write_image (RechterApfelBildOhneKerngehause, 'png', 0, 'C:/Users/blab1/Desktop/Apfel St„rke Test/EinzelneAepfel' + '/' + 'ApfelMitIod_' +SubstringsApfel[SubstringsApfelLength-1]) endfor