/* Process the images inside each directory */ bool processDir(std::string path, std::string image_name, std::string metrics_file) { /** Create the initial data collection skeleton **/ // Open the metrics file std::ofstream data_stream; data_stream.open(metrics_file, std::ios::app); if (!data_stream.is_open()) { std::cerr << "Could not open the data output file." << std::endl; return false; } // Create the output image directory std::string out_directory = path + "result/"; struct stat st = {0}; if (stat(out_directory.c_str(), &st) == -1) { mkdir(out_directory.c_str(), 0700); } // Analyzed image name std::string analyzed_image_name = image_name; std::size_t found = analyzed_image_name.find("dapi"); analyzed_image_name.replace(found, 4, "merge"); data_stream << analyzed_image_name << ","; /** Extract the dapi, gfp and rfp streams for each input image **/ // DAPI std::string in_filename = path + "jpg/" + image_name; cv::Mat dapi = cv::imread(in_filename.c_str(), -1); if (dapi.empty()) return false; // GFP std::string gfp_image_name = image_name; found = gfp_image_name.find("dapi"); gfp_image_name.replace(found, 4, "gfp"); in_filename = path + "jpg/" + gfp_image_name; cv::Mat gfp = cv::imread(in_filename.c_str(), -1); if (gfp.empty()) return false; // RFP std::string rfp_image_name = image_name; found = rfp_image_name.find("dapi"); rfp_image_name.replace(found, 4, "rfp"); in_filename = path + "jpg/" + rfp_image_name; cv::Mat rfp = cv::imread(in_filename.c_str(), -1); if (rfp.empty()) return false; /** Gather information needed for feature extraction **/ /* DAPI image */ // Enhance cv::Mat dapi_normalized, dapi_enhanced; if (!enhanceImage( dapi, ChannelType::DAPI, &dapi_normalized, &dapi_enhanced )) { return false; } // Segment cv::Mat dapi_segmented; std::vector<std::vector<cv::Point>> contours_dapi; std::vector<cv::Vec4i> hierarchy_dapi; std::vector<HierarchyType> dapi_contour_mask; std::vector<double> dapi_contour_area; contourCalc(dapi_enhanced, ChannelType::DAPI, 1.0, &dapi_segmented, &contours_dapi, &hierarchy_dapi, &dapi_contour_mask, &dapi_contour_area); // Filter the dapi contours std::vector<std::vector<cv::Point>> contours_dapi_filtered; filterCells(dapi_enhanced, contours_dapi, dapi_contour_mask, &contours_dapi_filtered); /* GFP image */ cv::Mat gfp_normalized, gfp_enhanced; if (!enhanceImage( gfp, ChannelType::GFP, &gfp_normalized, &gfp_enhanced )) { return false; } // GFP Low cv::Mat gfp_low_normalized, gfp_low_enhanced; if (!enhanceImage( gfp, ChannelType::GFP_LOW, &gfp_low_normalized, &gfp_low_enhanced )) { return false; } cv::Mat gfp_low_segmented; std::vector<std::vector<cv::Point>> contours_gfp_low; std::vector<cv::Vec4i> hierarchy_gfp_low; std::vector<HierarchyType> gfp_low_contour_mask; std::vector<double> gfp_low_contour_area; contourCalc(gfp_low_enhanced, ChannelType::GFP_LOW, 1.0, &gfp_low_segmented, &contours_gfp_low, &hierarchy_gfp_low, &gfp_low_contour_mask, &gfp_low_contour_area); // GFP Medium cv::Mat gfp_medium_normalized, gfp_medium_enhanced; if (!enhanceImage( gfp, ChannelType::GFP_MEDIUM, &gfp_medium_normalized, &gfp_medium_enhanced )) { return false; } cv::Mat gfp_medium_segmented; std::vector<std::vector<cv::Point>> contours_gfp_medium; std::vector<cv::Vec4i> hierarchy_gfp_medium; std::vector<HierarchyType> gfp_medium_contour_mask; std::vector<double> gfp_medium_contour_area; contourCalc(gfp_medium_enhanced, ChannelType::GFP_MEDIUM, 1.0, &gfp_medium_segmented, &contours_gfp_medium, &hierarchy_gfp_medium, &gfp_medium_contour_mask, &gfp_medium_contour_area); // GFP High cv::Mat gfp_high_normalized, gfp_high_enhanced; if (!enhanceImage( gfp, ChannelType::GFP_HIGH, &gfp_high_normalized, &gfp_high_enhanced )) { return false; } cv::Mat gfp_high_segmented; std::vector<std::vector<cv::Point>> contours_gfp_high; std::vector<cv::Vec4i> hierarchy_gfp_high; std::vector<HierarchyType> gfp_high_contour_mask; std::vector<double> gfp_high_contour_area; contourCalc(gfp_high_enhanced, ChannelType::GFP_HIGH, 1.0, &gfp_high_segmented, &contours_gfp_high, &hierarchy_gfp_high, &gfp_high_contour_mask, &gfp_high_contour_area); /* RFP image */ cv::Mat rfp_normalized, rfp_enhanced_type1; if (!enhanceImage( rfp, ChannelType::RFP_TYPE1, &rfp_normalized, &rfp_enhanced_type1 )) { return false; } cv::Mat rfp_enhanced_type2; if (!enhanceImage( rfp, ChannelType::RFP_TYPE2, &rfp_normalized, &rfp_enhanced_type2 )) { return false; } cv::Mat rfp_segmented; std::vector<std::vector<cv::Point>> contours_rfp_vec; std::vector<cv::Vec4i> hierarchy_rfp; std::vector<HierarchyType> rfp_contour_mask; std::vector<double> rfp_contour_area; contourCalc(rfp_enhanced_type2, ChannelType::RFP_TYPE2, 1.0, &rfp_segmented, &contours_rfp_vec, &hierarchy_rfp, &rfp_contour_mask, &rfp_contour_area); /* RFP Scatter plot */ // Determine whether the image is Control or SZ bool is_control = false; std::string sample_id = image_name.substr(0, 4); // Control - 3440, 3651, 4506, 9319, 9429, BJ2E, BJ3E if ( (sample_id == "3440") || (sample_id == "3651") || (sample_id == "4506") || (sample_id == "9319") || (sample_id == "9429") || (sample_id == "BJ2E") || (sample_id == "BJ3E") ) { is_control = true; } // Note: Do nothing for SZ - 1792, 1835, 2038, 2497 scatterPlot( path + PLOTS_DIR_NAME, is_control, rfp_normalized, contours_rfp_vec, rfp_contour_mask ); /** Classify the cell soma **/ std::vector<std::vector<cv::Point>> contours_gfp, contours_rfp; cv::Mat gfp_intersection = cv::Mat::zeros(gfp_enhanced.size(), CV_8UC1); cv::Mat rfp_intersection = cv::Mat::zeros(rfp_enhanced_type1.size(), CV_8UC1); for (size_t i = 0; i < contours_dapi_filtered.size(); i++) { // Find DAPI-GFP Cell Soma std::vector<cv::Point> gfp_contour; cv::Mat temp; if (findCellSoma( contours_dapi_filtered[i], gfp_enhanced, &temp, &gfp_contour )) { contours_gfp.push_back(gfp_contour); bitwise_or(gfp_intersection, temp, gfp_intersection); cv::Mat temp_not; bitwise_not(temp, temp_not); bitwise_and(gfp_enhanced, temp_not, gfp_enhanced); } // Find DAPI-RFP Cell Soma std::vector<cv::Point> rfp_contour; if (findCellSoma( contours_dapi_filtered[i], rfp_enhanced_type1, &temp, &rfp_contour )) { contours_rfp.push_back(rfp_contour); bitwise_or(rfp_intersection, temp, rfp_intersection); cv::Mat temp_not; bitwise_not(temp, temp_not); bitwise_and(rfp_enhanced_type1, temp_not, rfp_enhanced_type1); } } /** Collect the metrics **/ // Separation metrics for dapi-gfp cells float mean_dia = 0.0, stddev_dia = 0.0; float mean_aspect_ratio = 0.0, stddev_aspect_ratio = 0.0; float mean_error_ratio = 0.0, stddev_error_ratio = 0.0; separationMetrics( contours_gfp, &mean_dia, &stddev_dia, &mean_aspect_ratio, &stddev_aspect_ratio, &mean_error_ratio, &stddev_error_ratio ); data_stream << contours_gfp.size() << "," << mean_dia << "," << stddev_dia << "," << mean_aspect_ratio << "," << stddev_aspect_ratio << "," << mean_error_ratio << "," << stddev_error_ratio << ","; // Separation metrics for dapi-rfp cells mean_dia = 0.0; stddev_dia = 0.0; mean_aspect_ratio = 0.0; stddev_aspect_ratio = 0.0; mean_error_ratio = 0.0; stddev_error_ratio = 0.0; separationMetrics( contours_rfp, &mean_dia, &stddev_dia, &mean_aspect_ratio, &stddev_aspect_ratio, &mean_error_ratio, &stddev_error_ratio ); data_stream << contours_rfp.size() << "," << mean_dia << "," << stddev_dia << "," << mean_aspect_ratio << "," << stddev_aspect_ratio << "," << mean_error_ratio << "," << stddev_error_ratio << ","; /* Characterize the gfp channel */ // Gfp low std::string gfp_low_output; binArea(gfp_low_contour_mask, gfp_low_contour_area, &gfp_low_output); data_stream << gfp_low_output << ","; // Gfp medium std::string gfp_medium_output; binArea(gfp_medium_contour_mask, gfp_medium_contour_area, &gfp_medium_output); data_stream << gfp_medium_output << ","; // Gfp high std::string gfp_high_output; binArea(gfp_high_contour_mask, gfp_high_contour_area, &gfp_high_output); data_stream << gfp_high_output << ","; // End of entry data_stream << std::endl; data_stream.close(); /** Display the debug image **/ if (DEBUG_FLAG) { // Initialize cv::Mat drawing_blue_debug = cv::Mat::zeros(dapi_enhanced.size(), CV_8UC1); //cv::Mat drawing_blue_debug = 2*dapi_normalized; //cv::Mat drawing_green_debug = cv::Mat::zeros(gfp_enhanced.size(), CV_8UC1); cv::Mat drawing_green_debug = gfp_intersection; cv::Mat drawing_red_debug = cv::Mat::zeros(rfp_enhanced_type1.size(), CV_8UC1); //cv::Mat drawing_red_debug = rfp_intersection; // Draw DAPI bondaries for (size_t i = 0; i < contours_dapi_filtered.size(); i++) { cv::Moments mu = moments(contours_dapi_filtered[i], true); cv::Point2f mc = cv::Point2f( static_cast<float>(mu.m10/mu.m00), static_cast<float>(mu.m01/mu.m00) ); cv::circle(drawing_blue_debug, mc, DAPI_MASK_RADIUS, 255, 1, 8); cv::circle(drawing_green_debug, mc, DAPI_MASK_RADIUS, 255, 1, 8); cv::circle(drawing_red_debug, mc, DAPI_MASK_RADIUS, 255, 1, 8); } // Merge the modified red, blue and green layers std::vector<cv::Mat> merge_debug; merge_debug.push_back(drawing_blue_debug); merge_debug.push_back(drawing_green_debug); merge_debug.push_back(drawing_red_debug); cv::Mat color_debug; cv::merge(merge_debug, color_debug); // Draw the debug image std::string out_debug = out_directory + analyzed_image_name; out_debug.insert(out_debug.find_last_of("."), "_debug", 6); cv::imwrite(out_debug.c_str(), color_debug); } /** Display the analyzed <dapi,gfp,rfp> image set **/ // Initialize cv::Mat drawing_blue = 2*dapi_normalized; cv::Mat drawing_green = gfp_normalized; cv::Mat drawing_red = rfp_normalized; // Draw GFP bondaries for (size_t i = 0; i < contours_gfp.size(); i++) { //cv::RotatedRect min_ellipse = fitEllipse(cv::Mat(contours_gfp[i])); //ellipse(drawing_blue, min_ellipse, 255, 1, 8); //ellipse(drawing_green, min_ellipse, 255, 1, 8); //ellipse(drawing_red, min_ellipse, 0, 1, 8); drawContours(drawing_blue, contours_gfp, i, 255, 1, 8); drawContours(drawing_green, contours_gfp, i, 255, 1, 8); drawContours(drawing_red, contours_gfp, i, 0, 1, 8); } // Draw RFP bondaries for (size_t i = 0; i < contours_rfp.size(); i++) { //cv::RotatedRect min_ellipse = fitEllipse(cv::Mat(contours_rfp[i])); //ellipse(drawing_blue, min_ellipse, 255, 1, 8); //ellipse(drawing_green, min_ellipse, 0, 1, 8); //ellipse(drawing_red, min_ellipse, 255, 1, 8); drawContours(drawing_blue, contours_rfp, i, 255, 1, 8); drawContours(drawing_green, contours_rfp, i, 0, 1, 8); drawContours(drawing_red, contours_rfp, i, 255, 1, 8); } // Merge the modified red, blue and green layers std::vector<cv::Mat> merge_analyzed; merge_analyzed.push_back(drawing_blue); merge_analyzed.push_back(drawing_green); merge_analyzed.push_back(drawing_red); cv::Mat color_analyzed; cv::merge(merge_analyzed, color_analyzed); // Draw the analyzed image std::string out_analyzed = out_directory + analyzed_image_name; cv::imwrite(out_analyzed.c_str(), color_analyzed); return true; }
/* Process the images inside each directory */ bool processDir(std::string path, std::string image_name, std::string metrics_file) { /* Create the data output file for images that were processed */ std::ofstream data_stream; data_stream.open(metrics_file, std::ios::app); if (!data_stream.is_open()) { std::cerr << "Could not open the data output file." << std::endl; return false; } // Create the output directory std::string out_directory = path + "result/"; struct stat st = {0}; if (stat(out_directory.c_str(), &st) == -1) { mkdir(out_directory.c_str(), 0700); } out_directory = out_directory + image_name + "/"; st = {0}; if (stat(out_directory.c_str(), &st) == -1) { mkdir(out_directory.c_str(), 0700); } // Count the number of images std::string dir_name = path + "jpg/" + image_name + "/"; DIR *read_dir = opendir(dir_name.c_str()); if (!read_dir) { std::cerr << "Could not open directory '" << dir_name << "'" << std::endl; return false; } struct dirent *dir = NULL; uint8_t z_count = 0; bool collect_name_pattern = false; std::string end_pattern; while ((dir = readdir(read_dir))) { if (!strcmp (dir->d_name, ".") || !strcmp (dir->d_name, "..")) continue; if (!collect_name_pattern) { std::string delimiter = "c1+"; end_pattern = dir->d_name; size_t pos = end_pattern.find(delimiter); end_pattern.erase(0, pos); collect_name_pattern = true; } z_count++; } std::vector<cv::Mat> blue_list(NUM_Z_LAYERS_COMBINED), green_list(NUM_Z_LAYERS_COMBINED), red_list(NUM_Z_LAYERS_COMBINED); for (uint8_t z_index = 1; z_index <= z_count; z_index++) { // Create the input filename and rgb stream output filenames std::string in_filename; if (z_count < 10) { in_filename = dir_name + image_name + "_z" + std::to_string(z_index) + end_pattern; } else { if (z_index < 10) { in_filename = dir_name + image_name + "_z0" + std::to_string(z_index) + end_pattern; } else if (z_index < 100) { in_filename = dir_name + image_name + "_z" + std::to_string(z_index) + end_pattern; } else { // assuming number of z plane layers will never exceed 99 std::cerr << "Does not support more than 99 z layers curently" << std::endl; return false; } } // Extract the bgr streams for each input image cv::Mat img = cv::imread(in_filename.c_str(), -1); if (img.empty()) return false; // Original image std::string out_original = out_directory + "zlayer_" + std::to_string(z_index) + "_a_original.jpg"; if (DEBUG_FLAG) cv::imwrite(out_original.c_str(), img); std::vector<cv::Mat> channel(3); cv::split(img, channel); blue_list[(z_index-1)%NUM_Z_LAYERS_COMBINED] = channel[0]; green_list[(z_index-1)%NUM_Z_LAYERS_COMBINED] = channel[1]; red_list[(z_index-1)%NUM_Z_LAYERS_COMBINED] = channel[2]; // Continue collecting layers if needed //if (z_index%NUM_Z_LAYERS_COMBINED && (z_index != z_count)) continue; if (z_index < NUM_Z_LAYERS_COMBINED) continue; data_stream << image_name << "," << std::to_string(z_index - NUM_Z_LAYERS_COMBINED + 1) << "," << std::to_string(z_index) << ","; // Merge some layers together cv::Mat blue = cv::Mat::zeros(channel[0].size(), CV_8UC1); cv::Mat green = cv::Mat::zeros(channel[1].size(), CV_8UC1); cv::Mat red = cv::Mat::zeros(channel[1].size(), CV_8UC1); for (unsigned int merge_index = 0; merge_index < NUM_Z_LAYERS_COMBINED; merge_index++) { bitwise_or(blue, blue_list[merge_index], blue); bitwise_or(green, green_list[merge_index], green); bitwise_or(red, red_list[merge_index], red); } /** Gather BGR channel information needed for feature extraction **/ /* Enhance layers */ // Red channel cv::Mat red_enhanced; if(!enhanceImage(red, ChannelType::RED, &red_enhanced)) return false; std::string out_red = out_directory + "zlayer_" + std::to_string(z_index) + "_red_enhanced.jpg"; if (DEBUG_FLAG) cv::imwrite(out_red.c_str(), red_enhanced); // Purple channel cv::Mat purple_enhanced; if(!enhanceImage(red, ChannelType::PURPLE, &purple_enhanced)) return false; //cv::Mat red_enhanced_negative = cv::Mat::zeros(red_enhanced.size(), CV_8UC1); //bitwise_not(red_enhanced, red_enhanced_negative); //bitwise_and(purple_enhanced, red_enhanced_negative, purple_enhanced); std::string out_purple = out_directory + "zlayer_" + std::to_string(z_index) + "_purple_enhanced.jpg"; if (DEBUG_FLAG) cv::imwrite(out_purple.c_str(), purple_enhanced); // Blue channel cv::Mat blue_enhanced; if(!enhanceImage(blue, ChannelType::BLUE, &blue_enhanced)) return false; //cv::Mat purple_enhanced_negative = cv::Mat::zeros(purple_enhanced.size(), CV_8UC1); //bitwise_not(purple_enhanced, purple_enhanced_negative); //bitwise_and(blue_enhanced, purple_enhanced_negative, blue_enhanced); std::string out_blue = out_directory + "zlayer_" + std::to_string(z_index) + "_blue_enhanced.jpg"; if (DEBUG_FLAG) cv::imwrite(out_blue.c_str(), blue_enhanced); /* Segment */ // Blue channel cv::Mat blue_segmented; std::vector<std::vector<cv::Point>> contours_blue; std::vector<cv::Vec4i> hierarchy_blue; std::vector<HierarchyType> blue_contour_mask; std::vector<double> blue_contour_area; contourCalc( blue_enhanced, MIN_NUCLEUS_SIZE, &blue_segmented, &contours_blue, &hierarchy_blue, &blue_contour_mask, &blue_contour_area ); std::vector<std::vector<cv::Point>> contours_blue_filtered; filterCells( ChannelType::BLUE, blue_enhanced, contours_blue, blue_contour_mask, &contours_blue_filtered ); // Red channel cv::Mat red_segmented; std::vector<std::vector<cv::Point>> contours_red; std::vector<cv::Vec4i> hierarchy_red; std::vector<HierarchyType> red_contour_mask; std::vector<double> red_contour_area; contourCalc( red_enhanced, 1.0, &red_segmented, &contours_red, &hierarchy_red, &red_contour_mask, &red_contour_area ); /* Classify the cells */ std::vector<std::vector<cv::Point>> contours_neural_soma; std::vector<std::vector<cv::Point>> contours_neural_nuclei, contours_astrocytes; cv::Mat purple_intersection = cv::Mat::zeros(purple_enhanced.size(), CV_8UC1); for (size_t i = 0; i < contours_blue_filtered.size(); i++) { std::vector<cv::Point> purple_contour; cv::Mat temp; if (findCellSoma( contours_blue_filtered[i], purple_enhanced, &temp, &purple_contour )) { contours_neural_soma.push_back(purple_contour); contours_neural_nuclei.push_back(contours_blue_filtered[i]); bitwise_or(purple_intersection, temp, purple_intersection); cv::Mat temp_not; bitwise_not(temp, temp_not); bitwise_and(purple_enhanced, temp_not, purple_enhanced); } else { contours_astrocytes.push_back(contours_blue_filtered[i]); } } /** Collect the metrics **/ /* Cells */ data_stream << contours_blue_filtered.size() << ","; float mean_dia = 0.0, stddev_dia = 0.0; float mean_aspect_ratio = 0.0, stddev_aspect_ratio = 0.0; float mean_error_ratio = 0.0, stddev_error_ratio = 0.0; // Characterize neural nuclei separationMetrics( contours_neural_nuclei, &mean_dia, &stddev_dia, &mean_aspect_ratio, &stddev_aspect_ratio, &mean_error_ratio, &stddev_error_ratio ); data_stream << contours_neural_nuclei.size() << "," << mean_dia << "," << stddev_dia << "," << mean_aspect_ratio << "," << stddev_aspect_ratio << "," << mean_error_ratio << "," << stddev_error_ratio << ","; // Characterize the soma size separationMetrics( contours_neural_soma, &mean_dia, &stddev_dia, &mean_aspect_ratio, &stddev_aspect_ratio, &mean_error_ratio, &stddev_error_ratio ); data_stream << mean_dia << "," << stddev_dia << "," << mean_aspect_ratio << "," << stddev_aspect_ratio << "," << mean_error_ratio << "," << stddev_error_ratio << ","; // Characterize the astrocyte nuclei separationMetrics( contours_astrocytes, &mean_dia, &stddev_dia, &mean_aspect_ratio, &stddev_aspect_ratio, &mean_error_ratio, &stddev_error_ratio ); data_stream << contours_astrocytes.size() << "," << mean_dia << "," << stddev_dia << "," << mean_aspect_ratio << "," << stddev_aspect_ratio << "," << mean_error_ratio << "," << stddev_error_ratio << ","; /* Synapses */ std::string red_output; binArea(red_contour_mask, red_contour_area, &red_output); data_stream << red_output << ","; data_stream << std::endl; /** Display analyzed images **/ // Initialize cv::Mat drawing_blue = blue; cv::Mat drawing_green = green; cv::Mat drawing_red = red; // Draw soma for (size_t i = 0; i < contours_neural_soma.size(); i++) { drawContours(drawing_blue, contours_neural_soma, i, 255, 1, 8); drawContours(drawing_green, contours_neural_soma, i, 255, 1, 8); drawContours(drawing_red, contours_neural_soma, i, 255, 1, 8); } // Draw synapses for (size_t i = 0; i < contours_red.size(); i++) { drawContours(drawing_blue, contours_red, i, 0, 0, 8); drawContours(drawing_green, contours_red, i, 0, 0, 8); drawContours(drawing_red, contours_red, i, 255, -1, 8); } // Merge the modified red, blue and green layers std::vector<cv::Mat> merge_analyzed; merge_analyzed.push_back(drawing_blue); merge_analyzed.push_back(drawing_green); merge_analyzed.push_back(drawing_red); cv::Mat color_analyzed; cv::merge(merge_analyzed, color_analyzed); // Draw the analyzed image std::vector<int> compression_params; compression_params.push_back(CV_IMWRITE_JPEG_QUALITY); compression_params.push_back(101); cv::imwrite("/tmp/img.jpg", color_analyzed, compression_params); std::string out_analyzed = out_directory + "zlayer_" + std::to_string(z_index) + "_analyzed.tif"; std::string cmd = "convert -quiet /tmp/img.jpg " + out_analyzed; system(cmd.c_str()); system("rm /tmp/img.jpg"); } closedir(read_dir); data_stream.close(); return true; }
/* Process the images inside each directory */ bool processDir(std::string path, std::string image_name, std::string metrics_file) { /* Create the data output file for images that were processed */ std::ofstream data_stream; data_stream.open(metrics_file, std::ios::app); if (!data_stream.is_open()) { std::cerr << "Could not open the data output file." << std::endl; return false; } // Create the output directory std::string out_directory = path + "result/"; struct stat st = {0}; if (stat(out_directory.c_str(), &st) == -1) { mkdir(out_directory.c_str(), 0700); } out_directory = out_directory + image_name + "/"; st = {0}; if (stat(out_directory.c_str(), &st) == -1) { mkdir(out_directory.c_str(), 0700); } // Count the number of images std::string dir_name = path + "jpg/" + image_name + "/"; DIR *read_dir = opendir(dir_name.c_str()); if (!read_dir) { std::cerr << "Could not open directory '" << dir_name << "'" << std::endl; return false; } struct dirent *dir = NULL; uint8_t z_count = 0; bool collect_name_pattern = false; std::string end_pattern; while ((dir = readdir(read_dir))) { if (!strcmp (dir->d_name, ".") || !strcmp (dir->d_name, "..")) continue; if (!collect_name_pattern) { std::string delimiter = "c1+"; end_pattern = dir->d_name; size_t pos = end_pattern.find(delimiter); end_pattern.erase(0, pos); collect_name_pattern = true; } z_count++; } std::vector<cv::Mat> blue_list(NUM_Z_LAYERS_COMBINED), green_list(NUM_Z_LAYERS_COMBINED); for (uint8_t z_index = 1; z_index <= z_count; z_index++) { // Create the input filename and rgb stream output filenames std::string in_filename; if (z_count < 10) { in_filename = dir_name + image_name + "_z" + std::to_string(z_index) + end_pattern; } else { if (z_index < 10) { in_filename = dir_name + image_name + "_z0" + std::to_string(z_index) + end_pattern; } else if (z_index < 100) { in_filename = dir_name + image_name + "_z" + std::to_string(z_index) + end_pattern; } else { // assuming number of z plane layers will never exceed 99 std::cerr << "Does not support more than 99 z layers curently" << std::endl; return false; } } // Extract the bgr streams for each input image cv::Mat img = cv::imread(in_filename.c_str(), -1); if (img.empty()) return false; // Original image std::string out_original = out_directory + "zlayer_" + std::to_string(z_index) + "_a_original.jpg"; cv::imwrite(out_original.c_str(), img); std::vector<cv::Mat> channel(3); cv::split(img, channel); blue_list[(z_index-1)%NUM_Z_LAYERS_COMBINED] = channel[0]; green_list[(z_index-1)%NUM_Z_LAYERS_COMBINED] = channel[1]; // Continue collecting layers if needed if (z_index%NUM_Z_LAYERS_COMBINED && (z_index != z_count)) continue; // Merge some layers together cv::Mat blue = cv::Mat::zeros(channel[0].size(), CV_8UC1); cv::Mat green = cv::Mat::zeros(channel[1].size(), CV_8UC1); for (unsigned int merge_index = 0; merge_index < NUM_Z_LAYERS_COMBINED; merge_index++) { bitwise_or(blue, blue_list[merge_index], blue); bitwise_or(green, green_list[merge_index], green); } /** Gather BGR channel information needed for feature extraction **/ // Blue channel std::string out_blue = out_directory + "zlayer_" + std::to_string(z_index) + "_blue.jpg"; if (DEBUG_FLAG) cv::imwrite(out_blue.c_str(), blue); cv::Mat blue_enhanced; if(!enhanceImage(blue, ChannelType::BLUE, &blue_enhanced)) return false; out_blue.insert(out_blue.find_last_of("."), "_enhanced", 9); if (DEBUG_FLAG) cv::imwrite(out_blue.c_str(), blue_enhanced); cv::Mat blue_segmented; std::vector<std::vector<cv::Point>> contours_blue; std::vector<cv::Vec4i> hierarchy_blue; std::vector<HierarchyType> blue_contour_mask; std::vector<double> blue_contour_area; contourCalc(blue_enhanced, ChannelType::BLUE, 1.0, &blue_segmented, &contours_blue, &hierarchy_blue, &blue_contour_mask, &blue_contour_area); // Green channel std::string out_green = out_directory + "zlayer_" + std::to_string(z_index) + "_green.jpg"; if (DEBUG_FLAG) cv::imwrite(out_green.c_str(), green); cv::Mat green_enhanced; if(!enhanceImage(green, ChannelType::GREEN, &green_enhanced)) return false; out_green.insert(out_green.find_last_of("."), "_enhanced", 9); if (DEBUG_FLAG) cv::imwrite(out_green.c_str(), green_enhanced); cv::Mat not_blue, green_minus_blue, green_skeletonize; bitwise_not(blue_enhanced, not_blue); bitwise_and(green_enhanced, not_blue, green_minus_blue); skeletonize(green_enhanced, &green_skeletonize); out_green.insert(out_green.find_last_of("."), "_skeletonized", 13); if (DEBUG_FLAG) cv::imwrite(out_green.c_str(), green_skeletonize); cv::Mat green_segmented; std::vector<std::vector<cv::Point>> contours_green; std::vector<cv::Vec4i> hierarchy_green; std::vector<HierarchyType> green_contour_mask; std::vector<double> green_contour_area; contourCalc(green_enhanced, ChannelType::GREEN, 1.0, &green_segmented, &contours_green, &hierarchy_green, &green_contour_mask, &green_contour_area); } closedir(read_dir); data_stream.close(); return true; }
int main(int argc, char *argv[]) { image myPic; imageInfo picInfo; int count; char *outputType = NULL; int err; int aCrop = NO; int left = -1, right = -1, top = -1, bottom = -1; double xscale = 1, yscale = 1; double xs2, ys2; int xdim = 0, ydim = 0; int ditherMode = ' '; int mMono = NO; int outType = NO; int scaletofit = NO; int numBits = 1; char *outFile = NULL; char *type = NULL, *ext = NULL; char *p; int nv; double darken = 0; double contrast = 0; double rotate = 0; struct stat sbuf; int blend = NO; static char filename[MAXPATHLEN + 1] = ""; int negative = NO; int enhance = NO; formatInfo fInfo; count = getargs(argc, argv, "nbosabLiRiTiBixdydXiYidcmbpbsbbiDdSbKdfseird", &negative, &outputType, &aCrop, &left, &right, &top, &bottom, &xscale, &yscale, &xdim, &ydim, &ditherMode, &mMono, &outType, &scaletofit, &numBits, &darken, &blend, &contrast, &outFile, &enhance, &rotate ); if (count < 0 || count == argc) { if (count < 0 && -count != '-') fprintf(stderr, "Bad flag: %c\n", -count); fprintf(stderr, "Usage: %s [-options] filename\n" " options:\n" "\tn: make negative\n" "\to: string indicating output format\n" "\ta: auto crop non plotting areas\n" "\tL, R, T, B: specify where to crop picture\n" "\tx, y: specify scale factor in that direction\n" "\tX, Y: specify dimension of picture in that direction\n" "\td: select dither method: (D)ither, (T)hreshold, or (H)alftone\n" "\tm: convert image to monochrome\n" "\tp: dither image for output to printer\n" "\ts: scale image to fill up specified screen\n" "\tb: number of bits to dither to\n" "\tD: how much to brighten image\n" "\tK: contrast level\n" "\tS: blend pixels together when scaling\n" "\tf: file name to save to\n" "\te: contrast for enhance image\n" "\tr: number of degrees to rotate\n" , *argv); exit(1); } for (; count < argc; count++) { if ((err = load_pic(argv[count], &myPic))) { fprintf(stderr, "Cannot load file %s\nError: %s\n", argv[count], picErrorStr(err)); exit(1); } if (!getImageInfo(argv[count], &picInfo)) type = picInfo.extension; if (!outputType) outputType = type; if (!infoForFormat(outputType, &fInfo)) { ext = fInfo.extension; if (scaletofit && !xdim && !ydim && fInfo.maxWidth && fInfo.maxHeight) { xdim = fInfo.maxWidth; ydim = fInfo.maxHeight; } } if (mMono) makeMono(&myPic); if (left >= 0 || right >= 0 || top >= 0 || bottom >= 0) { if (left < 0) left = 0; if (right < 0) right = myPic.width - 1; if (top < 0) top = 0; if (bottom < 0) bottom = myPic.height - 1; cropImage(left, top, right, bottom, &myPic); } if (aCrop) autoCropImage(&myPic, 40); if (rotate) rotateImage(&myPic, (rotate * -3.141592) / 180.0); xs2 = xscale; ys2 = yscale; if (scaletofit) { if (!ydim && xdim) { xs2 = (double) xdim / ((double) myPic.width * xscale) * xscale; ys2 = ((double) xdim / ((double) myPic.width * xscale)) * yscale; } else if (ydim) { xs2 = ((double) ydim / ((double) myPic.height * yscale)) * xscale; ys2 = (double) ydim / ((double) myPic.height * yscale) * yscale; if (xdim && (myPic.width * xs2) > xdim) { xs2 = (double) xdim / ((double) myPic.width * xscale) * xscale; ys2 = ((double) xdim / ((double) myPic.width * xscale)) * yscale; } } } else { if (xdim) xs2 = (double) xdim / (double) myPic.width; if (ydim) ys2 = (double) ydim / (double) myPic.height; } xscale = xs2; yscale = ys2; scaleImage(xscale, yscale, blend, &myPic); if (darken || contrast) adjustImage(&myPic, contrast, darken); if (enhance) { makeMono(&myPic); enhanceImage(&myPic, enhance); } handle_dithering(ditherMode, &myPic, outType, numBits); if (negative) negateImage(&myPic); if (outFile) { strcpy(filename, outFile); if (!stat(filename, &sbuf) && (sbuf.st_mode & S_IFDIR)) { if (filename[strlen(filename) - 1] != '/') strcat(filename, "/"); if ((p = strrchr(argv[count], '/'))) strcat(filename, p + 1); else strcat(filename, argv[count]); } } else strcpy(filename, argv[count]); p = change_extension(filename, type, ext, 0); nv = 2; while (!stat(p, &sbuf)) { p = change_extension(filename, type, ext, nv); nv++; } if ((err = save_pic(p, outputType, &myPic))) { fprintf(stderr, "Cannot save file %s\nError: %s\n", p, picErrorStr(err)); exit(1); } fprintf(stderr, "Saved %s as %s\n", argv[count], p); freeImage(&myPic); } exit(0); return 0; }