|
| 1 | +/**+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| 2 | +
|
| 3 | +This file is part of FORCE - Framework for Operational Radiometric |
| 4 | +Correction for Environmental monitoring. |
| 5 | +
|
| 6 | +Copyright (C) 2013-2024 David Frantz |
| 7 | +
|
| 8 | +FORCE is free software: you can redistribute it and/or modify |
| 9 | +it under the terms of the GNU General Public License as published by |
| 10 | +the Free Software Foundation, either version 3 of the License, or |
| 11 | +(at your option) any later version. |
| 12 | +
|
| 13 | +FORCE is distributed in the hope that it will be useful, |
| 14 | +but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | +GNU General Public License for more details. |
| 17 | +
|
| 18 | +You should have received a copy of the GNU General Public License |
| 19 | +along with FORCE. If not, see <http://www.gnu.org/licenses/>. |
| 20 | +
|
| 21 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++**/ |
| 22 | + |
| 23 | +/**+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| 24 | +This program computes a histogram of the given image |
| 25 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++**/ |
| 26 | + |
| 27 | + |
| 28 | +#include <stdio.h> // core input and output functions |
| 29 | +#include <stdlib.h> // standard general utilities library |
| 30 | + |
| 31 | +#include <ctype.h> // testing and mapping characters |
| 32 | +#include <unistd.h> // standard symbolic constants and types |
| 33 | + |
| 34 | +#include "../cross-level/const-cl.h" |
| 35 | +#include "../cross-level/utils-cl.h" |
| 36 | +#include "../cross-level/konami-cl.h" |
| 37 | +#include "../cross-level/string-cl.h" |
| 38 | +#include "../cross-level/table-cl.h" |
| 39 | + |
| 40 | +/** Geospatial Data Abstraction Library (GDAL) **/ |
| 41 | +#include "gdal.h" // public (C callable) GDAL entry points |
| 42 | + |
| 43 | + |
| 44 | +typedef struct { |
| 45 | + int n; |
| 46 | + int band; |
| 47 | + char file_input[NPOW_10]; |
| 48 | + char file_output[NPOW_10]; |
| 49 | +} args_t; |
| 50 | + |
| 51 | + |
| 52 | +void usage(char *exe, int exit_code){ |
| 53 | + |
| 54 | + |
| 55 | + printf("Usage: %s [-h] [-v] [-i] [-b band] [-o output-file] input-image\n", exe); |
| 56 | + printf("\n"); |
| 57 | + printf(" -h = show this help\n"); |
| 58 | + printf(" -v = show version\n"); |
| 59 | + printf(" -i = show program's purpose\n"); |
| 60 | + printf("\n"); |
| 61 | + printf(" -b band = band to use,\n"); |
| 62 | + printf(" defaults to 1\n"); |
| 63 | + printf("\n"); |
| 64 | + printf(" -o output-file = output file path with extension,\n"); |
| 65 | + printf(" defaults to './histogram.csv'\n"); |
| 66 | + printf("\n"); |
| 67 | + printf(" Positional arguments:\n"); |
| 68 | + printf(" - 'input-image': image for computing the histogram\n"); |
| 69 | + printf("\n"); |
| 70 | + |
| 71 | + exit(exit_code); |
| 72 | + return; |
| 73 | +} |
| 74 | + |
| 75 | + |
| 76 | +void parse_args(int argc, char *argv[], args_t *args){ |
| 77 | +int opt; |
| 78 | + |
| 79 | + |
| 80 | + opterr = 0; |
| 81 | + |
| 82 | + // default parameters |
| 83 | + copy_string(args->file_output, NPOW_10, "histogram.csv"); |
| 84 | + args->band = 1; |
| 85 | + |
| 86 | + // optional parameters |
| 87 | + while ((opt = getopt(argc, argv, "hvio:b:")) != -1){ |
| 88 | + switch(opt){ |
| 89 | + case 'h': |
| 90 | + usage(argv[0], SUCCESS); |
| 91 | + case 'v': |
| 92 | + get_version(NULL, 0); |
| 93 | + exit(SUCCESS); |
| 94 | + case 'i': |
| 95 | + printf("Compute image histogram\n"); |
| 96 | + exit(SUCCESS); |
| 97 | + case 'o': |
| 98 | + copy_string(args->file_output, NPOW_10, optarg); |
| 99 | + break; |
| 100 | + case 'b': |
| 101 | + args->band = atoi(optarg); |
| 102 | + if (args->band < 1){ |
| 103 | + fprintf(stderr, "Band must be >= 1\n"); |
| 104 | + usage(argv[0], FAILURE); |
| 105 | + } |
| 106 | + break; |
| 107 | + case '?': |
| 108 | + if (isprint(optopt)){ |
| 109 | + fprintf(stderr, "Unknown option `-%c'.\n", optopt); |
| 110 | + } else { |
| 111 | + fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt); |
| 112 | + } |
| 113 | + usage(argv[0], FAILURE); |
| 114 | + default: |
| 115 | + fprintf(stderr, "Error parsing arguments.\n"); |
| 116 | + usage(argv[0], FAILURE); |
| 117 | + } |
| 118 | + } |
| 119 | + |
| 120 | + // non-optional parameters |
| 121 | + args->n = 1; |
| 122 | + |
| 123 | + if (optind < argc){ |
| 124 | + konami_args(argv[optind]); |
| 125 | + if (argc-optind == args->n){ |
| 126 | + copy_string(args->file_input, NPOW_10, argv[optind++]); |
| 127 | + } else if (argc-optind < args->n){ |
| 128 | + fprintf(stderr, "some non-optional arguments are missing.\n"); |
| 129 | + usage(argv[0], FAILURE); |
| 130 | + } else if (argc-optind > args->n){ |
| 131 | + fprintf(stderr, "too many non-optional arguments.\n"); |
| 132 | + usage(argv[0], FAILURE); |
| 133 | + } |
| 134 | + } else { |
| 135 | + fprintf(stderr, "non-optional arguments are missing.\n"); |
| 136 | + usage(argv[0], FAILURE); |
| 137 | + } |
| 138 | + |
| 139 | + return; |
| 140 | +} |
| 141 | + |
| 142 | + |
| 143 | +int main(int argc, char *argv[]){ |
| 144 | +args_t args; |
| 145 | +GDALDatasetH fp; |
| 146 | +GDALRasterBandH band; |
| 147 | +int i, j, nx, ny, nbands; |
| 148 | +short *line = NULL; |
| 149 | +short nodata; |
| 150 | +int has_nodata; |
| 151 | +int offset = SHRT_MAX+1; |
| 152 | +int length = USHRT_MAX+1; |
| 153 | +table_t counts; |
| 154 | +int row; |
| 155 | + |
| 156 | + |
| 157 | + parse_args(argc, argv, &args); |
| 158 | + |
| 159 | + GDALAllRegister(); |
| 160 | + if ((fp = GDALOpen(args.file_input, GA_ReadOnly)) == NULL){ |
| 161 | + fprintf(stderr, "could not open %s.\n", args.file_input); exit(1);} |
| 162 | + |
| 163 | + nx = GDALGetRasterXSize(fp); |
| 164 | + ny = GDALGetRasterYSize(fp); |
| 165 | + nbands = GDALGetRasterCount(fp); |
| 166 | + |
| 167 | + alloc((void**)&line, nx, sizeof(short)); |
| 168 | + |
| 169 | + if (args.band > nbands){ |
| 170 | + fprintf(stderr, "Input image has %d band(s), band %d was requested.\n", nbands, args.band); exit(1);} |
| 171 | + band = GDALGetRasterBand(fp, args.band); |
| 172 | + |
| 173 | + nodata = (short)GDALGetRasterNoDataValue(band, &has_nodata); |
| 174 | + if (!has_nodata){ |
| 175 | + fprintf(stderr, "input image has no nodata value.\n"); |
| 176 | + exit(1); |
| 177 | + } |
| 178 | + |
| 179 | + |
| 180 | + counts = allocate_table(length, 2, false, true); |
| 181 | + copy_string(counts.col_names[0], NPOW_10, "class"); |
| 182 | + copy_string(counts.col_names[1], NPOW_10, "count"); |
| 183 | + for (row=0; row<counts.nrow; row++) counts.data[row][0] = row - offset; |
| 184 | + |
| 185 | + for (i=0; i<ny; i++){ |
| 186 | + |
| 187 | + if (GDALRasterIO(band, GF_Read, 0, i, nx, 1, |
| 188 | + line, nx, 1, GDT_Int16, 0, 0) == CE_Failure){ |
| 189 | + fprintf(stderr, "could not read line %d.\n", i+1); exit(1);} |
| 190 | + |
| 191 | + for (j=0; j<nx; j++){ |
| 192 | + |
| 193 | + if (line[j] == nodata) continue; |
| 194 | + |
| 195 | + row = line[j] + offset; |
| 196 | + counts.data[row][1]++; |
| 197 | + |
| 198 | + } |
| 199 | + |
| 200 | + } |
| 201 | + |
| 202 | + GDALClose(fp); |
| 203 | + |
| 204 | + free((void*)line); |
| 205 | + |
| 206 | + |
| 207 | + for (row=0; row<counts.nrow; row++){ |
| 208 | + if (counts.data[row][1] == 0) counts.row_mask[row] = false; |
| 209 | + } |
| 210 | + |
| 211 | + write_table(&counts, args.file_output, ",", true); |
| 212 | + |
| 213 | + free_table(&counts); |
| 214 | + |
| 215 | + return SUCCESS; |
| 216 | +} |
| 217 | + |
0 commit comments