Coord searchForLetter(Array2D<char> const& wsArray, char c, Coord const& start) { /** * @brief This function searches each row starting at the point start for the * letter c. When it reaches the end of the row, it sets the x-coordinate * to search for and goes down another row. */ unsigned x = start.pX; for (unsigned y = start.pY; y < wsArray.getHeight(); ++y) { while (x < wsArray.getWidth()) { //If the first character matches, check the word out. if (wsArray(x, y) == c) return Coord(x, y); ++x; } x = 0; } return Coord(wsArray.getWidth(), wsArray.getHeight()); }
T Mask2D<T>::get(size_t n, Array2D<V> array, size_t h, size_t w) { #ifdef __CUDA_ARCH__ h += this->deviceMask[this->dimension*n]; w += this->deviceMask[this->dimension*n+1]; return (w<array.getWidth() && h<array.getHeight())?array(h,w):this->haloValue; #else h += this->hostMask[this->dimension*n]; w += this->hostMask[this->dimension*n+1]; return (w<array.getWidth() && h<array.getHeight())?array(h,w):this->haloValue; #endif }
bool isWordAtGivenDir(Array2D<char> const& wsArray, std::string str, Coord const& coord, Direction dir) { /** * @brief Given the array to search in, the string to find, this function * specifies whether or not the string is found at the position * coord in the direction dir. */ //First check if the word can be entirely contained within the wordsearch's //bounds. if ((coord.pX + (str.size() - 1) * dir.dX < 0) || (coord.pX + (str.size() - 1) * dir.dX >= wsArray.getWidth()) || (coord.pY + (str.size() - 1) * dir.dY < 0) || (coord.pY + (str.size() - 1) * dir.dY >= wsArray.getHeight())) return false; //If you see any letter that doesn't match, you're done. for (unsigned i = 0; i != str.size(); ++i) { if (str[i] != wsArray(coord.pX + i * dir.dX, coord.pY + i * dir.dY)) return false; } //One arrives here if and only if no letters that don't match are encountered, //i.e., the word IS found at the given coordinates and direction. return true; }
POIvec extractPOIs(const Array2D<float> &eval, float threshold) { int w = eval.getWidth(), h = eval.getHeight(); POIvec all; for(int y=0; y<h; y++) for(int x=0; x<w; x++) if(eval[y][x] >= threshold) all.push_back(POI(x,y,eval[y][x])); std::sort(all.begin(), all.end()); return all; }
void RawParameters::autoWB(const Array2D<uint16_t> & image) { Timer t("AutoWB"); double dsum[4] = { 0.0, 0.0, 0.0, 0.0 }; size_t dcount[4] = { 0, 0, 0, 0 }; for (size_t row = 0; row < image.getHeight(); row += 8) { for (size_t col = 0; col < image.getWidth() ; col += 8) { double sum[4] = { 0.0, 0.0, 0.0, 0.0 }; size_t count[4] = { 0, 0, 0, 0 }; size_t ymax = std::min(row + 8, image.getHeight()); size_t xmax = std::min(col + 8, image.getWidth()); bool skipBlock = false; for (size_t y = row; y < ymax && !skipBlock; y++) { for (size_t x = col; x < xmax; x++) { int c = FC(x, y); uint16_t val = image(x, y); if (val > max - 25) { skipBlock = true; break; } sum[c] += val; count[c]++; } } if (!skipBlock) { for (int c = 0; c < 4; ++c) { dsum[c] += sum[c]; dcount[c] += count[c]; } } } } for (int c = 0; c < 4; ++c) { if (dsum[c] > 0.0) { camMul[c] = dcount[c] / dsum[c]; } else { copy_n(preMul, 4, camMul); break; } } }
Image visualizeEvaluation(const Array2D<float> &eval) { int w = eval.getWidth(), h = eval.getHeight(); float max = 0; for(int y = 0; y < h; y++) for(int x = 0; x < w; x++) max = std::max(max, eval[y][x]); Image ret(w,h); for(int y=0; y<h; y++) for(int x=0; x<w; x++) ret[y][x] = round(eval[y][x]/max*255.f); return ret; }
void setOccupied(Array2D<VecStr>& occupied, std::string str, Coord const& coord, Direction const& dir) { //Assert that you remain in the bounds; this is a "private" function, and //you should never leave the bounds when wsSolve() is called. assert((coord.pX + (str.size() - 1) * dir.dX >= 0) && (coord.pX + (str.size() - 1) * dir.dX < occupied.getWidth()) && (coord.pY + (str.size() - 1) * dir.dY >= 0) && (coord.pY + (str.size() - 1) * dir.dY < occupied.getHeight())); //For each block that this string occupies, show that the block is occupied by //the string. for (unsigned i = 0; i < str.size(); ++i) occupied(coord.pX + i * dir.dX, coord.pY + i * dir.dY).push_back(str); }
bool areAllOccupiedBySuperstring(Array2D<VecStr> const& occupied, std::string str, Coord const& coord, Direction const& dir) { /** * @brief Given the array of squares in the wordsearch that are occupied, * we check to see if the word str is "allowed" to be at the coord * of ld and have direction dir. See wsSolveDoc.h for more information * on what's "allowed" and what's not. */ //Assert that you remain in the bounds; this is a "private" function, and //you should never leave the bounds when wsSolve() is called. assert((coord.pX + (str.size() - 1) * dir.dX >= 0) && (coord.pX + (str.size() - 1) * dir.dX < occupied.getWidth()) && (coord.pY + (str.size() - 1) * dir.dY >= 0) && (coord.pY + (str.size() - 1) * dir.dY < occupied.getHeight())); //The string's length can't be 0. assert(str.size() != 0); //First check if the square that the first letter of str occupies is occupied //by any superstring of str. If not, exit; if so, make a list of them. VecStr firstVecStr = occupied(coord.pX, coord.pY); if (firstVecStr.size() == 0) return false; //Executes iff above code didn't return false. VecStr possibleSuperstrList; for (unsigned i = 0; i != firstVecStr.size(); ++i) { //The below statement is equivalent to "if str is not a substring of //firstVecStr[i]. if (firstVecStr[i].find(str) == std::string::npos) return false; else possibleSuperstrList.push_back(firstVecStr[i]); } //If the string is only one letter long, and we didn't return false yet, it means //that the string is on a spot occupied by one of its superstrings. Hence, we //return true. if (str.size() == 1) return true; //Something important to note is that str can only be a substring of any //superstring of str if its first is contained by a superstring of str. //Therefore, the set of all possible superstrings of str that overlap with str //entirely has already been determined. In the following code, we either find a //square which is empty or does not contain a superstring of str (and therefore //we return false) or find a square in which some element of possibleSuperstrList //is not found on the square (implying that that element is not a superstring of //str that overlaps with str entirely; make sure you see why); we therefore //remove that element from possibleSuperStrList. In the end, any remaining elements //in possibleSuperstrList is definitely a superstring of str that overlaps with //str entirely; hence, if it is empty by the end, this function returns false, //and if it isn't empty, this function returns true. for (unsigned i = 1; i < str.size(); ++i) { //Vector obtained at the current position in the array. VecStr vecStrCurrent = occupied(coord.pX + i * dir.dX, coord.pY + i * dir.dY); //List of superstrings of str on the current square. VecStr superstrListCurrent; //If the vector is empty, the position is unoccupied. if (vecStrCurrent.size() == 0) return false; //See if str is a substring of any strings currently held in vecStrCurrent. for (unsigned j = 0; j != vecStrCurrent.size(); ++j) { //The below statement is equivalent to "if str is not a substring of //vecStrCurrent[i]. if (vecStrCurrent[j].find(str) == std::string::npos) return false; else superstrListCurrent.push_back(vecStrCurrent[j]); } //Get rid of all the elements of possibleSuperstrList that don't appear in //vecSuperStrListCurrent. We do this by creating a new vector containing all //elements that DO appear in vecSuperStrListCurrent, and then copy //possibleSuperstrList to the new one. VecStr newPossibleSuperstrList; for (unsigned j = 0; j != possibleSuperstrList.size(); ++j) { for (unsigned k = 0; k != superstrListCurrent.size(); ++k) { if (possibleSuperstrList[j] == superstrListCurrent[k]) { newPossibleSuperstrList.push_back(possibleSuperstrList[j]); break; } } } possibleSuperstrList = newPossibleSuperstrList; //If it's empty, you're done. if (possibleSuperstrList.size() == 0) return false; } //Reached if and only if the above code doesn't execute. return true; }
void wsSolve(Array2D<char> const& wsArray, //Wordsearch array to solve. StrLocMap& matchMap) //List of words and their locations { /** * @brief Given the array (wsArray) and the list of words to find (domain of * matchMap), wsSolve will fill the range of matchMap with the locations * of the words to find. For instance, if matchMap contains * (string1, locationData), wsSolve() fills in locationData * with the location of the string. If the word is not found, * locationData will remain unmodified. * * The algorithm itself is quite complex. See wsSolveDoc.h for more * information. * * @author MPW * @date 7/19/2008 * @version 1 * */ typedef std::vector<Coord> CoordVec; //Declare the array of vectors of strings and set them all to empty vectors. Array2D<VecStr> occupied(wsArray.getWidth(), wsArray.getHeight()); for (unsigned y = 0; y != wsArray.getHeight(); ++y) { for (unsigned x = 0; x != wsArray.getWidth(); ++x) occupied(x, y) = std::vector<std::string>(); } //Find the list of letters to make a location list for, and for each letter, //pair the letter with a vector containing the coordinates of each occurrence //of that letter. //We go through the list, finding each letter to cache. std::map<char, CoordVec> cacheList; char prevChar = 0; char currentChar = 0; for (StrLocMap::iterator itr = matchMap.begin(); itr != matchMap.end();) { //currentChar is still from the previous loop! Hence, we set prevChar to //currentChar and update currentChar. prevChar = currentChar; currentChar = itr->first[0]; //If the letter here is the same as the one before, it repeats (since //maps sort their elements in alphabetical order) (if this is //the first loop, this will never happen; prevChar will be nul, and no first //letter of a string can be nul; therefore, we don't count the first element //as appearing twice). if (currentChar == prevChar) { cacheList.insert(std::make_pair(currentChar, CoordVec())); //This trasverses the map until we get to a different character. while ((++itr != matchMap.end()) && (itr->first[0] == currentChar)); //This is so the ++itr below does not execute. continue; } ++itr; } //Copy each of the strings into a multimap; this will sort the strings by //length. std::multimap<unsigned, std::string> strList; for (StrLocMap::iterator itr = matchMap.begin(); itr != matchMap.end(); ++itr) strList.insert(std::make_pair(itr->first.size(), itr->first)); //Start the find. for (std::multimap<unsigned, std::string>::reverse_iterator itr = strList.rbegin(); itr != strList.rend(); ++itr) { std::string& str = itr->second; bool isCached = !(cacheList.find(str[0]) == cacheList.end()); //Whether or not //the first letter //of the current //string is //cached. Coord startLocation(0, 0); //Location to start searching at; if the first //letter of the word's locations have been cached, //and none of the cached positions are the //location where str is found, startLocation is //set to the spot one after the last cached //position. if (isCached) { CoordVec& coordVec = cacheList[str[0]]; if (coordVec.size() != 0) { //We assert here that the cached locations are in "ascending order"; //see wsSolveDoc.h for more information. for (unsigned i = 0; i != coordVec.size(); ++i) { //Contains the list of all possible directions the word can have //at the given coordinates; see wsSolveDoc.h for more information. std::vector<Direction> possibleDirList; findWordAt(wsArray, str, coordVec[i], possibleDirList); //Go through the vector, either until we find a valid direction //the word can have, or until there are no possible directions //the word can have left. (There's a chance possibleDir.empty() is //already true, so in that case, just skip over that part.) for (std::vector<Direction>::iterator itr2 = possibleDirList.begin(); itr2 != possibleDirList.end(); ++itr2) { if (!areAllOccupiedBySuperstring(occupied, str, coordVec[i], *itr2)) { //You found the word! matchMap[str] = LocationData(coordVec[i], *itr2); setOccupied(occupied, str, coordVec[i], *itr2); goto lblContinue; } } } } } //If the word was found in a cache, we skip over to lblContinue; however, we //would then be skipping over some variable declarations in the current //scope. This is banned by C++ syntax, so we wrap the following code in //another block. { Coord const endLocation(wsArray.getWidth(), wsArray.getHeight()); Coord location(startLocation); //Find the next occurrence of the character you're searching for. while ((location = searchForLetter(wsArray, str[0], location)) != endLocation) { //Cache this position (if relevant). if (isCached) cacheList[str[0]].push_back(location); //Contains the list of all possible directions the word can have //at the given coordinates; see wsSolveDoc.h for more information. std::vector<Direction> possibleDirList; findWordAt(wsArray, str, location, possibleDirList); for (std::vector<Direction>::iterator itr2 = possibleDirList.begin(); itr2 != possibleDirList.end(); ++itr2) { if (!areAllOccupiedBySuperstring(occupied, str, location, *itr2)) { //You found the word! matchMap[str] = LocationData(location, *itr2); setOccupied(occupied, str, location, *itr2); //You're done with this loop; you then enter the next loop //(i.e., you search for the next string.) goto lblContinue; } } //Increase the location's position by 1; if it goes past the end of //the row, go down another row. if (location.pX < wsArray.getWidth()) ++location.pX; else { if (location.pY < wsArray.getHeight()) { //This code executes if you're on the last position on the //last row; in that case, you're done. ++location.pY; location.pX = 0; } else break; } } } lblContinue: continue; } }
// From The GIMP: app/paint-funcs/paint-funcs.c:fatten_region // SSE version by Ingo Weyrich static Array2D<uint8_t> fattenMask(const Array2D<uint8_t> & mask, int radius) { Timer t("Fatten mask (SSE version)"); size_t width = mask.getWidth(), height = mask.getHeight(); Array2D<uint8_t> result(width, height); int circArray[2 * radius + 1]; // holds the y coords of the filter's mask // compute_border(circArray, radius) for (int i = 0; i < radius * 2 + 1; i++) { double tmp; if (i > radius) tmp = (i - radius) - 0.5; else if (i < radius) tmp = (radius - i) - 0.5; else tmp = 0.0; circArray[i] = int(std::sqrt(radius*radius - tmp*tmp)); } // offset the circ pointer by radius so the range of the array // is [-radius] to [radius] int * circ = circArray + radius; const uint8_t * bufArray[height + 2*radius]; for (int i = 0; i < radius; i++) { bufArray[i] = &mask[0]; } for (size_t i = 0; i < height; i++) { bufArray[i + radius] = &mask[i * width]; } for (int i = 0; i < radius; i++) { bufArray[i + height + radius] = &mask[(height - 1) * width]; } // offset the buf pointer const uint8_t ** buf = bufArray + radius; #pragma omp parallel { uint8_t buffer[width * (radius + 1)]; uint8_t *maxArray[radius+1]; for (int i = 0; i <= radius; i++) { maxArray[i] = &buffer[i*width]; } #pragma omp for schedule(dynamic,16) for (size_t y = 0; y < height; y++) { size_t x = 0; for (; x < width-15; x+=16) { // compute max array, use SSE to process 16 bytes at once __m128i lmax = _mm_loadu_si128((__m128i*)&buf[y][x]); if(radius<2) // max[0] is only used when radius < 2 _mm_storeu_si128((__m128i*)&maxArray[0][x],lmax); for (int i = 1; i <= radius; i++) { lmax = _mm_max_epu8(_mm_loadu_si128((__m128i*)&buf[y + i][x]),lmax); lmax = _mm_max_epu8(_mm_loadu_si128((__m128i*)&buf[y - i][x]),lmax); _mm_storeu_si128((__m128i*)&maxArray[i][x],lmax); } } for (; x < width; x++) { // compute max array, remaining columns uint8_t lmax = buf[y][x]; if(radius<2) // max[0] is only used when radius < 2 maxArray[0][x] = lmax; for (int i = 1; i <= radius; i++) { lmax = std::max(std::max(lmax, buf[y + i][x]), buf[y - i][x]); maxArray[i][x] = lmax; } } for (x = 0; (int)x < radius; x++) { // render scan line, first columns without SSE uint8_t last_max = maxArray[circ[radius]][x+radius]; for (int i = radius - 1; i >= -(int)x; i--) last_max = std::max(last_max,maxArray[circ[i]][x + i]); result(x, y) = last_max; } for (; x < width-15-radius+1; x += 16) { // render scan line, use SSE to process 16 bytes at once __m128i last_maxv = _mm_loadu_si128((__m128i*)&maxArray[circ[radius]][x+radius]); for (int i = radius - 1; i >= -radius; i--) last_maxv = _mm_max_epu8(last_maxv,_mm_loadu_si128((__m128i*)&maxArray[circ[i]][x+i])); _mm_storeu_si128((__m128i*)&result(x,y),last_maxv); } for (; x < width; x++) { // render scan line, last columns without SSE int maxRadius = std::min(radius,(int)((int)width-1-(int)x)); uint8_t last_max = maxArray[circ[maxRadius]][x+maxRadius]; for (int i = maxRadius-1; i >= -radius; i--) last_max = std::max(last_max,maxArray[circ[i]][x + i]); result(x, y) = last_max; } } } return result; }
// From The GIMP: app/paint-funcs/paint-funcs.c:fatten_region static Array2D<uint8_t> fattenMask(const Array2D<uint8_t> & mask, int radius) { Timer t("Fatten mask"); size_t width = mask.getWidth(), height = mask.getHeight(); Array2D<uint8_t> result(width, height); int circArray[2 * radius + 1]; // holds the y coords of the filter's mask // compute_border(circArray, radius) for (int i = 0; i < radius * 2 + 1; i++) { double tmp; if (i > radius) tmp = (i - radius) - 0.5; else if (i < radius) tmp = (radius - i) - 0.5; else tmp = 0.0; circArray[i] = int(std::sqrt(radius*radius - tmp*tmp)); } // offset the circ pointer by radius so the range of the array // is [-radius] to [radius] int * circ = circArray + radius; const uint8_t * bufArray[height + 2*radius]; for (int i = 0; i < radius; i++) { bufArray[i] = &mask[0]; } for (size_t i = 0; i < height; i++) { bufArray[i + radius] = &mask[i * width]; } for (int i = 0; i < radius; i++) { bufArray[i + height + radius] = &mask[(height - 1) * width]; } // offset the buf pointer const uint8_t ** buf = bufArray + radius; #pragma omp parallel { unique_ptr<uint8_t[]> buffer(new uint8_t[width * (radius + 1)]); unique_ptr<uint8_t *[]> maxArray; // caches the largest values for each column maxArray.reset(new uint8_t *[width + 2 * radius]); for (int i = 0; i < radius; i++) { maxArray[i] = buffer.get(); } for (size_t i = 0; i < width; i++) { maxArray[i + radius] = &buffer[(radius + 1) * i]; } for (int i = 0; i < radius; i++) { maxArray[i + width + radius] = &buffer[(radius + 1) * (width - 1)]; } // offset the max pointer uint8_t ** max = maxArray.get() + radius; #pragma omp for schedule(dynamic) for (size_t y = 0; y < height; y++) { uint8_t rowMax = 0; for (size_t x = 0; x < width; x++) { // compute max array max[x][0] = buf[y][x]; for (int i = 1; i <= radius; i++) { max[x][i] = std::max(std::max(max[x][i - 1], buf[y + i][x]), buf[y - i][x]); rowMax = std::max(max[x][i], rowMax); } } uint8_t last_max = max[0][circ[-1]]; int last_index = 1; for (size_t x = 0; x < width; x++) { // render scan line last_index--; if (last_index >= 0) { if (last_max == rowMax) { result(x, y) = rowMax; } else { last_max = 0; for (int i = radius; i >= 0; i--) if (last_max < max[x + i][circ[i]]) { last_max = max[x + i][circ[i]]; last_index = i; } result(x, y) = last_max; } } else { last_index = radius; last_max = max[x + radius][circ[radius]]; for (int i = radius - 1; i >= -radius; i--) if (last_max < max[x + i][circ[i]]) { last_max = max[x + i][circ[i]]; last_index = i; } result(x, y) = last_max; } } } } return result; }