wrong perspective image after taking picture on accelerometer supported blackberry device - blackberry

There is a perspective image issue when I read a picture that is taken from the camera. When the direction is north, the picture looks like needed to be rotated 270 degrees. When the direction is east, picture should be rotated 180 degrees. But it's good when the direction is west. I tried getMetaData().getKeyValue("orientation") in EncodedImage for producing a good rotating formula, but it returned empty string. Please help me how to solve this problem.

Found solution here:
https://gist.github.com/3788313
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.EncodedImage;
public class ExifRotate {
/**
* Flip the image horizontally.
*/
public static final int FLIP_H = 1;
/**
* Flip the image vertically.
*/
public static final int FLIP_V = 2;
/**
* Flip the image horizontally and vertically.
*/
public static final int FLIP_HV = 3;
/**
* Rotate the image 90 degrees clockwise.
*/
public static final int FLIP_90CW = 4;
/**
* Rotate the image 90 degrees counter-clockwise.
*/
public static final int FLIP_90CCW = 5;
/**
* Rotate the image 180 degrees.
*/
public static final int FLIP_180 = 6;
private final static int read2bytes(InputStream in) throws IOException {
return in.read() << 8 | in.read();
}
private final static int readByte(InputStream in) throws IOException {
return in.read();
}
public static Bitmap readImageFromFile(String filename, int width, int height) throws IOException {
EncodedImage img = null;
byte[] data = null;
FileConnection file = null;
try {
file = (FileConnection) Connector.open(filename, Connector.READ);
int fileSize = (int) file.fileSize();
if (fileSize == 0) {
throw new IOException("File is empty");
}
data = new byte[fileSize];
InputStream input = file.openInputStream();
input.read(data);
input.close();
img = EncodedImage.createEncodedImage(data, 0, data.length);
int orientation = -1;
if ( filename.toLowerCase().endsWith(".jpg") || filename.toLowerCase().endsWith(".jpeg")) {
ByteArrayInputStream is = new ByteArrayInputStream( data );
orientation = getRotation(is);
}
if ( orientation == 2 ) {
return rotateBitmap(img.getBitmap(), ImageUtil.FLIP_H);
} else if ( orientation == 3 ) {
return rotateBitmap(img.getBitmap(), ImageUtil.FLIP_180);
} else if ( orientation == 4 ) {
return rotateBitmap(img.getBitmap(), ImageUtil.FLIP_V);
} else if ( orientation == 5 ) {
Bitmap tmp = rotateBitmap(img.getBitmap(), ImageUtil.FLIP_H);
tmp = rotateBitmap(tmp, ImageUtil.FLIP_90CCW);
return tmp;
} else if ( orientation == 6 ) {
return rotateBitmap(img.getBitmap(), ImageUtil.FLIP_90CW);
} else if ( orientation == 7 ) {
Bitmap tmp = rotateBitmap(img.getBitmap(), ImageUtil.FLIP_H);
tmp = rotateBitmap(tmp, ImageUtil.FLIP_90CW);
return tmp;
} else if ( orientation == 8 ) {
return rotateBitmap(img.getBitmap(), ImageUtil.FLIP_90CCW);
} else {
return img.getBitmap();
}
} finally {
if (file != null) {
try { file.close(); }
catch(Exception ex){}
}
}
}
public static int getRotation(InputStream in) throws IOException {
int [] exif_data = new int[100];
int n_flag = 0, set_flag = 0;
int is_motorola = 0;
/* Read File head, check for JPEG SOI + Exif APP1 */
for (int i = 0; i < 4; i++)
exif_data[i] = readByte(in);
if (exif_data[0] != 0xFF || exif_data[1] != 0xD8 || exif_data[2] != 0xFF || exif_data[3] != 0xE1)
return -2;
/* Get the marker parameter length count */
int length = read2bytes(in);
// exif_data = new int[length];
/* Length includes itself, so must be at least 2 */
/* Following Exif data length must be at least 6 */
if (length < 8)
return -1;
length -= 8;
/* Read Exif head, check for "Exif" */
for (int i = 0; i < 6; i++)
exif_data[i] = in.read();
if (exif_data[0] != 0x45 || exif_data[1] != 0x78 || exif_data[2] != 0x69 || exif_data[3] != 0x66 || exif_data[4] != 0 || exif_data[5] != 0)
return -1;
/* Read Exif body */
length = length > exif_data.length ? exif_data.length : length;
for (int i = 0; i < length; i++)
exif_data[i] = in.read();
if (length < 12)
return -1; /* Length of an IFD entry */
/* Discover byte order */
if (exif_data[0] == 0x49 && exif_data[1] == 0x49)
is_motorola = 0;
else if (exif_data[0] == 0x4D && exif_data[1] == 0x4D)
is_motorola = 1;
else
return -1;
/* Check Tag Mark */
if (is_motorola == 1) {
if (exif_data[2] != 0)
return -1;
if (exif_data[3] != 0x2A)
return -1;
} else {
if (exif_data[3] != 0)
return -1;
if (exif_data[2] != 0x2A)
return -1;
}
/* Get first IFD offset (offset to IFD0) */
int offset;
if (is_motorola == 1) {
if (exif_data[4] != 0)
return -1;
if (exif_data[5] != 0)
return -1;
offset = exif_data[6];
offset <<= 8;
offset += exif_data[7];
} else {
if (exif_data[7] != 0)
return -1;
if (exif_data[6] != 0)
return -1;
offset = exif_data[5];
offset <<= 8;
offset += exif_data[4];
}
if (offset > length - 2)
return -1; /* check end of data segment */
/* Get the number of directory entries contained in this IFD */
int number_of_tags;
if (is_motorola == 1) {
number_of_tags = exif_data[offset];
number_of_tags <<= 8;
number_of_tags += exif_data[offset + 1];
} else {
number_of_tags = exif_data[offset + 1];
number_of_tags <<= 8;
number_of_tags += exif_data[offset];
}
if (number_of_tags == 0)
return -1;
offset += 2;
/* Search for Orientation Tag in IFD0 */
for (;;) {
if (offset > length - 12)
return -1; /* check end of data segment */
/* Get Tag number */
int tagnum;
if (is_motorola == 1) {
tagnum = exif_data[offset];
tagnum <<= 8;
tagnum += exif_data[offset + 1];
} else {
tagnum = exif_data[offset + 1];
tagnum <<= 8;
tagnum += exif_data[offset];
}
if (tagnum == 0x0112)
break; /* found Orientation Tag */
if (--number_of_tags == 0)
return -1;
offset += 12;
}
/*
* if (set_flag==1) { Set the Orientation value if (is_motorola==1) {
* exif_data[offset+2] = 0; Format = unsigned short (2 octets)
* exif_data[offset+3] = 3; exif_data[offset+4] = 0; Number Of
* Components = 1 exif_data[offset+5] = 0; exif_data[offset+6] = 0;
* exif_data[offset+7] = 1; exif_data[offset+8] = 0; exif_data[offset+9]
* = set_flag; exif_data[offset+10] = 0; exif_data[offset+11] = 0; }
* else { exif_data[offset+2] = 3; Format = unsigned short (2 octets)
* exif_data[offset+3] = 0; exif_data[offset+4] = 1; Number Of
* Components = 1 exif_data[offset+5] = 0; exif_data[offset+6] = 0;
* exif_data[offset+7] = 0; exif_data[offset+8] = set_flag;
* exif_data[offset+9] = 0; exif_data[offset+10] = 0;
* exif_data[offset+11] = 0; } }
*/
// else {
/* Get the Orientation value */
if (is_motorola == 1) {
if (exif_data[offset + 8] != 0)
return -1;
set_flag = exif_data[offset + 9];
} else {
if (exif_data[offset + 9] != 0)
return -1;
set_flag = exif_data[offset + 8];
}
if (set_flag > 8)
return -1;
// }
/* Write out Orientation value */
if (n_flag == 1)
System.out.println("set_flag " + set_flag);
else
System.out.println("set_flag " + set_flag);
return set_flag;
}
public static Bitmap rotateBitmap(Bitmap src, int operation) {
int width = src.getWidth();
int height = src.getHeight();
int[] inPixels = new int[width*height];
src.getARGB(inPixels, 0, width, 0, 0, width, height);
int x = 0, y = 0;
int w = width;
int h = height;
int newX = 0;
int newY = 0;
int newW = w;
int newH = h;
switch (operation) {
case FLIP_H:
newX = width - (x + w);
break;
case FLIP_V:
newY = height - (y + h);
break;
case FLIP_HV:
newW = h;
newH = w;
newX = y;
newY = x;
break;
case FLIP_90CW:
newW = h;
newH = w;
newX = height - (y + h);
newY = x;
break;
case FLIP_90CCW:
newW = h;
newH = w;
newX = y;
newY = width - (x + w);
break;
case FLIP_180:
newX = width - (x + w);
newY = height - (y + h);
break;
}
int[] newPixels = new int[newW * newH];
int index, newRow, newCol, newIndex;
if ( operation == FLIP_H ) {
for (int row = 0; row < h; row++) {
for (int col = 0; col < w; col++) {
index = row * width + col;
newRow = row;
newCol = w - col - 1;
newIndex = newRow * newW + newCol;
newPixels[newIndex] = inPixels[index];
}
}
} else if ( operation == FLIP_V ) {
for (int row = 0; row < h; row++) {
for (int col = 0; col < w; col++) {
index = row * width + col;
newRow = h - row - 1;
newCol = col;
newIndex = newRow * newW + newCol;
newPixels[newIndex] = inPixels[index];
}
}
} else if ( operation == FLIP_HV ) {
for (int row = 0; row < h; row++) {
for (int col = 0; col < w; col++) {
index = row * width + col;
newRow = col;
newCol = row;
newIndex = newRow * newW + newCol;
newPixels[newIndex] = inPixels[index];
}
}
} else if ( operation == FLIP_90CW ) {
for (int row = 0; row < h; row++) {
for (int col = 0; col < w; col++) {
index = row * width + col;
newRow = col;
newCol = h - row - 1;
newIndex = newRow * newW + newCol;
newPixels[newIndex] = inPixels[index];
}
}
} else if ( operation == FLIP_90CCW ) {
for (int row = 0; row < h; row++) {
for (int col = 0; col < w; col++) {
index = row * width + col;
newRow = w - col - 1;
newCol = row;
newIndex = newRow * newW + newCol;
newPixels[newIndex] = inPixels[index];
}
}
} else if ( operation == FLIP_180 ) {
for (int row = 0; row < h; row++) {
for (int col = 0; col < w; col++) {
index = row * width + col;
newRow = h - row - 1;
newCol = w - col - 1;
newIndex = newRow * newW + newCol;
newPixels[newIndex] = inPixels[index];
}
}
}
Bitmap dst = new Bitmap( newW, newH );
dst.setARGB(newPixels, 0, newW, 0, 0, newW, newH);
return dst;
}
}

Related

I get this error when I try to compile my code for CS50 week 4 filter-less

I am doing Week 4 Filter-less for CS50, I get an error whne I try to compile my code
When I complie it is see this erorr.
/usr/bin/ld: /lib/x86_64-linux-gnu/Scrt1.o: in function _start': (.text+0x1b): undefined reference to main'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [: helpers] Error 1
This is my code
#include "helpers.h"
#include <math.h>
// Convert image to grayscale
void grayscale(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
float r = image[i][j].rgbtRed;
float g = image[i][j].rgbtGreen;
float b = image[i][j].rgbtBlue;
float grey = round((b + g + r)/3.0);
image[i][j].rgbtRed = image[i][j].rgbtGreen = image[i][j].rgbtBlue = grey;
}
}
return;
}
// Convert image to sepia
void sepia(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width / 2; j++)
{
int w = width - (j + 1);
RGBTRIPLE tmp = image[i][j];
image[i][j] = image[i][w];
image[i][w] = tmp;
}
}
return;
}
// Reflect image horizontally
void reflect(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int b = image[i][j].rgbtBlue;
int g = image[i][j].rgbtGreen;
int r = image[i][j].rgbtRed;
int sepiaRed = round((0.393 * r) + (0.769 * g) + (0.189 * b));
int sepiaGreen = round((0.349 * r) + (0.686 * g) + (0.168 * b));
int sepiaBlue = round((0.272 * r) + (0.534 * g) + (0.131 * b));
if (sepiaRed > 255)
{
sepiaRed = 255;
}
if (sepiaGreen > 255)
{
sepiaGreen = 255;
}
if (sepiaBlue > 255)
{
sepiaBlue = 255;
}
image[i][j].rgbtBlue = sepiaBlue;
image[i][j].rgbtGreen = sepiaGreen;
image[i][j].rgbtRed = sepiaRed;
}
}
return;
}
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE tmp[height][width];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
tmp[i][j] = image[i][j];
}
}
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int totalRed = 0;
int totalGreen = 0;
int totalBlue = 0;
float counter = 0.00;
for (int x = -1; x < 2; x++)
{
for (int y = -1; y < 2; y++)
{
int X = i + x;
int Y = j + y;
if (X < 0 || Y < 0 || X > (height - 1) || Y > (width - 1))
{
continue;
}
totalRed += image[X][Y].rgbtRed;
totalGreen += image[X][Y].rgbtGreen;
totalBlue += image[X][Y].rgbtBlue;
counter++;
}
tmp[i][j].rgbtRed = round(totalRed / counter);
tmp[i][j].rgbtGreen = round(totalGreen / counter);
tmp[i][j].rgbtBlue = round(totalBlue / counter);
}
}
}
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
image[i][j].rgbtRed = tmp[i][j].rgbtRed;
image[i][j].rgbtGreen = tmp[i][j].rgbtGreen;
image[i][j].rgbtBlue = tmp[i][j].rgbtBlue;
}
}
return;
}

Arrows segmentations in an image

I need a way to segment each arrow alone. I tried OpenCv findContours but it broke it or add it to multiple shapes and arrows as the share the boundaries of shapes. I tried OpenCV connected components but this arrows almost in some graph connected all of it. Plus having trouble as the boundaries almost have the same color as the arrow. And in these kind of images each arrow contains different colors. Any opinion about this problem.
This is a sample diagram. I have to deal with harder diagrams like this.
Ok, work with new picture.
1. Binarization the arrows (and shapes):
cv::Mat imgCl = cv::imread("62uoU.jpg", cv::IMREAD_COLOR);
cv::Mat img;
cv::cvtColor(imgCl, img, cv::COLOR_BGR2GRAY);
cv::Mat mask1;
cv::threshold(img, mask1, 30, 255, cv::THRESH_BINARY_INV);
cv::Mat mask2;
cv::threshold(img, mask2, 120, 255, cv::THRESH_BINARY_INV);
cv::Mat diff;
cv::absdiff(mask1, mask2, diff);
cv::imshow("diff1", diff);
Result 1:
Remove rectangle shapes:
cv::Rect objRect(0, 0, diff.cols, diff.rows);
cv::Size minSize(objRect.width / 100, objRect.height / 100);
cv::Mat bin = cv::Mat(diff, objRect).clone();
for (;;)
{
cv::Rect cutRect;
if (!PosRefinement(bin, cutRect, 0.9f, minSize))
{
break;
}
cv::rectangle(bin, cutRect, cv::Scalar(0, 0, 0), cv::FILLED);
cv::rectangle(diff, cutRect, cv::Scalar(0, 0, 0), cv::FILLED);
objRect.x += cutRect.x;
objRect.y += cutRect.y;
objRect.width = cutRect.width;
objRect.height = cutRect.height;
}
cv::imshow("diff", diff);
Result 2:
Find lines:
std::vector<cv::Vec4i> linesP;
cv::HoughLinesP(diff, linesP, 1, CV_PI / 180, 20, 10, 5);
for (size_t i = 0; i < linesP.size(); i++)
{
cv::Vec4i l = linesP[i];
cv::line(imgCl, cv::Point(l[0], l[1]), cv::Point(l[2], l[3]), cv::Scalar(0, 0, 255), 3, cv::LINE_AA);
}
cv::imshow("img", imgCl);
Result 3:
Black arrows was founded. It can to improve this solution: find and delete text areas from image (tesseract or cv::text::ERFilter). And add a little morphology for draw arrow tips with Hough lines.
P.S. Utility function:
bool PosRefinement(
cv::Mat bin,
cv::Rect& cutRect,
double kThreshold,
cv::Size minSize
)
{
const double areaThreshold = 100;
const int radius = 5;
const int maxIters = 100;
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(bin, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE, cv::Point());
size_t bestCont = contours.size();
double maxArea = 0;
for (size_t i = 0; i < contours.size(); i++)
{
double area = cv::contourArea(contours[i]);
if (area > maxArea)
{
maxArea = area;
bestCont = i;
}
}
if (maxArea < areaThreshold)
{
return false;
}
cv::Moments m = cv::moments(contours[bestCont]);
cv::Point mc(cvRound(m.m10 / m.m00), cvRound(m.m01 / m.m00));
cv::Rect currRect(mc.x - radius / 2, mc.y - radius / 2, radius, radius);
auto Clamp = [](int v, int hi) -> bool
{
if (v < 0)
{
v = 0;
return true;
}
else if (hi && v > hi - 1)
{
v = hi - 1;
return true;
}
return false;
};
auto RectClamp = [&](cv::Rect& r, int w, int h) -> bool
{
return Clamp(r.x, w) || Clamp(r.x + r.width, w) || Clamp(r.y, h) || Clamp(r.y + r.height, h);
};
int stepL = radius / 2;
int stepR = radius / 2;
int stepT = radius / 2;
int stepB = radius / 2;
double k = 0;
struct State
{
double k = 0;
int stepL = 0;
int stepR = 0;
int stepT = 0;
int stepB = 0;
cv::Rect currRect;
State() = default;
State(double k_, int stepL_, int stepR_, int stepT_, int stepB_, cv::Rect currRect_)
:
k(k_),
stepL(stepL_),
stepR(stepR_),
stepT(stepT_),
stepB(stepB_),
currRect(currRect_)
{
}
bool operator==(const State& st) const
{
return (st.k == k) && (st.stepL == stepL) && (st.stepR == stepR) && (st.stepT == stepT) && (st.stepB == stepB) && (st.currRect == currRect);
}
};
const size_t statesCount = 2;
State prevStates[statesCount];
size_t stateInd = 0;
for (int it = 0; it < maxIters; ++it)
{
cv::Rect rleft(currRect.x - stepL, currRect.y, currRect.width + stepL, currRect.height);
cv::Rect rright(currRect.x, currRect.y, currRect.width + stepR, currRect.height);
cv::Rect rtop(currRect.x, currRect.y - stepT, currRect.width, currRect.height + stepT);
cv::Rect rbottom(currRect.x, currRect.y, currRect.width, currRect.height + stepB);
double kleft = 0;
double kright = 0;
double ktop = 0;
double kbottom = 0;
if (!RectClamp(rleft, bin.cols, bin.rows))
{
cv::Rect rstep(currRect.x - stepL, currRect.y, stepL, currRect.height);
if (cv::sum(bin(rstep))[0] / (255.0 * rstep.area()) > kThreshold / 2)
{
kleft = cv::sum(bin(rleft))[0] / (255.0 * rleft.area());
}
}
if (!RectClamp(rright, bin.cols, bin.rows))
{
cv::Rect rstep(currRect.x + currRect.width, currRect.y, stepR, currRect.height);
if (cv::sum(bin(rstep))[0] / (255.0 * rstep.area()) > kThreshold / 2)
{
kright = cv::sum(bin(rright))[0] / (255.0 * rright.area());
}
}
if (!RectClamp(rtop, bin.cols, bin.rows))
{
cv::Rect rstep(currRect.x, currRect.y - stepT, currRect.width, stepT);
if (cv::sum(bin(rstep))[0] / (255.0 * rstep.area()) > kThreshold / 2)
{
ktop = cv::sum(bin(rtop))[0] / (255.0 * rtop.area());
}
}
if (!RectClamp(rbottom, bin.cols, bin.rows))
{
cv::Rect rstep(currRect.x, currRect.y + currRect.height, currRect.width, stepB);
if (cv::sum(bin(rstep))[0] / (255.0 * rstep.area()) > kThreshold / 2)
{
kbottom = cv::sum(bin(rbottom))[0] / (255.0 * rbottom.area());
}
}
bool wasEnlargeX = false;
if (kleft > kThreshold)
{
currRect.x -= stepL;
currRect.width += stepL;
wasEnlargeX = true;
if (kleft > k)
{
++stepL;
}
}
else
{
if (stepL > 1)
{
--stepL;
}
currRect.x += 1;
currRect.width -= 1;
}
if (kright > kThreshold)
{
currRect.width += stepR;
wasEnlargeX = true;
if (kright > k)
{
++stepR;
}
}
else
{
if (stepR > 1)
{
--stepR;
}
currRect.width -= 1;
}
bool wasEnlargeY = false;
if (ktop > kThreshold)
{
currRect.y -= stepT;
currRect.height += stepT;
wasEnlargeY = true;
if (ktop > k)
{
++stepT;
}
}
else
{
if (stepT > 1)
{
--stepT;
}
currRect.y += 1;
currRect.height -= 1;
}
if (kbottom > kThreshold)
{
currRect.height += stepB;
wasEnlargeY = true;
if (kbottom > k)
{
++stepB;
}
}
else
{
if (stepB > 1)
{
--stepB;
}
currRect.height -= 1;
}
k = cv::sum(bin(currRect))[0] / (255.0 * currRect.area());
State currState(k, stepL, stepR, stepT, stepB, currRect);
bool repState = false;
for (size_t i = 0; i < statesCount; ++i)
{
if (prevStates[i] == currState)
{
repState = true;
break;
}
}
if (repState)
{
break;
}
else
{
prevStates[stateInd] = currState;
stateInd = (stateInd + 1 < statesCount) ? (stateInd + 1) : 0;
}
if (k < kThreshold && (stepL + stepR + stepT + stepB == 4) && !wasEnlargeX && !wasEnlargeY)
{
break;
}
}
cutRect.x = std::max(0, currRect.x - 1);
cutRect.width = currRect.width + 2;
cutRect.y = std::max(0, currRect.y - 1);
cutRect.height = currRect.height + 2;
return (cutRect.width >= minSize.width) && (cutRect.height >= minSize.height);
}
For your example it might be simple. The picture (png) has 4 channels and 4th channel is transparent mask. It can work only with transparent channel and filter arrows with moments:
cv::Mat img = cv::imread("voXFs.png", cv::IMREAD_UNCHANGED);
std::cout << "imsize = " << img.size() << ", chans = " << img.channels() << std::endl;
cv::imshow("img", img);
std::vector<cv::Mat> chans;
cv::split(img, chans);
cv::imshow("transp", chans.back());
cv::Mat mask;
cv::threshold(chans.back(), mask, 50, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
std::vector<std::vector<cv::Point> > contours;
cv::findContours(mask, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
cv::Mat draw;
cv::cvtColor(mask, draw, cv::COLOR_GRAY2BGR);
for (size_t i = 0; i < contours.size(); ++i)
{
double area = cv::contourArea(contours[i]);
double len = cv::arcLength(contours[i], false);
double k = len / area;
if (area > 10 && len > 60 && k > 2)
{
std::cout << "area = " << area << ", len = " << len << ", k = " << k << std::endl;
cv::drawContours(draw, contours, i, cv::Scalar(255, 0, 0), 1);
}
}
cv::imshow("mask", mask);
cv::imshow("draw", draw);
cv::waitKey(0);
But for more robust result:
Find and delete text areas from image (tesseract or cv::text::ERFilter).
Erode mask, find all shapes by contours, draw and dilate they. Bitwise and operation for mask and result.
The end!

Can I create Fill and Eraser tools for winrt app like paint app in windows by Win2d or sharpdx?

I tried to create Fill and Eraser Tools by GDI but this way is too slow for windows phone devices and work with large photos with this method is too hard for this divices.
I search for Alternative soulation for Image Processing and find Win2D and Sharpdx but not sure These Api can help me for create these tools.
this is Fill tool in winrtxamltoolkit
public static void FloodFill(this WriteableBitmap target, int x, int y, int outlineColor, int fillColor, byte maxdiff)
{
var width = target.PixelWidth;
var height = target.PixelHeight;
var queue = new List<Pnt>();
using (var context = target.GetBitmapContext(ReadWriteMode.ReadWrite))
{
queue.Add(new Pnt { X = x, Y = y });
while (queue.Count > 0)
{
var p = queue[queue.Count - 1];
queue.RemoveAt(queue.Count - 1);
if (p.X == -1) continue;
if (p.X == width) continue;
if (p.Y == -1) continue;
if (p.Y == height) continue;
if (context.Pixels[width * p.Y + p.X] == outlineColor) continue;
if (context.Pixels[width * p.Y + p.X] == fillColor) continue;
if (context.Pixels[width * p.Y + p.X].MaxDiff(outlineColor) > maxdiff)
{
context.Pixels[width * p.Y + p.X] = fillColor;
}
else
{
continue;
}
context.Pixels[width * p.Y + p.X] = fillColor;
queue.Add(new Pnt { X = p.X, Y = p.Y - 1 });
queue.Add(new Pnt { X = p.X + 1, Y = p.Y });
queue.Add(new Pnt { X = p.X, Y = p.Y + 1 });
queue.Add(new Pnt { X = p.X - 1, Y = p.Y });
}
target.Invalidate();
}
}
and this is Ereaser tool in WriteableBitmapEx
public static void FillEllipseCenteredTrsnceparent(this WriteableBitmap bmp, int xc, int yc, int xr, int yr, Color color)
{
using (BitmapContext context = bmp.GetBitmapContext())
{
Func<Color, int> toInt32 = c =>
{
var i = ((((c.A << 0x18) | (((c.R * c.A + 1) >> 8) << 0x10)) | (((c.G * c.A + 1) >> 8) << 8)) | ((c.B * c.A + 1) >> 8));
return i;
};
int[] pixels = context.Pixels;
int width = context.Width;
int height = context.Height;
if ((xr >= 1) && (yr >= 1))
{
int num3;
int num4;
int num5;
int num6;
int num7;
int num8;
int num9 = xr;
int num10 = 0;
int num11 = (xr * xr) << 1;
int num12 = (yr * yr) << 1;
int num13 = (yr * yr) * (1 - (xr << 1));
int num14 = xr * xr;
int num15 = 0;
int num16 = num12 * xr;
int num17 = 0;
//int sa = (color >> 0x18) & 0xff;
//int sr = (color >> 0x10) & 0xff;
//int sg = (color >> 8) & 0xff;
//int sb = color & 0xff;
//bool flag = !doAlphaBlend || (sa == 0xff);
while (num16 >= num17)
{
num5 = yc + num10;
num6 = yc - num10;
if (num5 < 0)
{
num5 = 0;
}
if (num5 >= height)
{
num5 = height - 1;
}
if (num6 < 0)
{
num6 = 0;
}
if (num6 >= height)
{
num6 = height - 1;
}
num3 = num5 * width;
num4 = num6 * width;
num8 = xc + num9;
num7 = xc - num9;
if (num8 < 0)
{
num8 = 0;
}
if (num8 >= width)
{
num8 = width - 1;
}
if (num7 < 0)
{
num7 = 0;
}
if (num7 >= width)
{
num7 = width - 1;
}
for (int i = num7; i <= num8; i++)
{
pixels[i + num3] = toInt32(color);
pixels[i + num4] = toInt32(color);
}
num10++;
num17 += num11;
num15 += num14;
num14 += num11;
if ((num13 + (num15 << 1)) > 0)
{
num9--;
num16 -= num12;
num15 += num13;
num13 += num12;
}
}
num9 = 0;
num10 = yr;
num5 = yc + num10;
num6 = yc - num10;
if (num5 < 0)
{
num5 = 0;
}
if (num5 >= height)
{
num5 = height - 1;
}
if (num6 < 0)
{
num6 = 0;
}
if (num6 >= height)
{
num6 = height - 1;
}
num3 = num5 * width;
num4 = num6 * width;
num13 = yr * yr;
num14 = (xr * xr) * (1 - (yr << 1));
num15 = 0;
num16 = 0;
num17 = num11 * yr;
while (num16 <= num17)
{
num8 = xc + num9;
num7 = xc - num9;
if (num8 < 0)
{
num8 = 0;
}
if (num8 >= width)
{
num8 = width - 1;
}
if (num7 < 0)
{
num7 = 0;
}
if (num7 >= width)
{
num7 = width - 1;
}
for (int j = num7; j <= num8; j++)
{
pixels[j + num3] = toInt32(color);
pixels[j + num4] = toInt32(color);
}
num9++;
num16 += num12;
num15 += num13;
num13 += num12;
if ((num14 + (num15 << 1)) > 0)
{
num10--;
num5 = yc + num10;
num6 = yc - num10;
if (num5 < 0)
{
num5 = 0;
}
if (num5 >= height)
{
num5 = height - 1;
}
if (num6 < 0)
{
num6 = 0;
}
if (num6 >= height)
{
num6 = height - 1;
}
num3 = num5 * width;
num4 = num6 * width;
num17 -= num11;
num15 += num14;
num14 += num11;
}
}
}
}
}
Is there a way to conver this code to win2d or Sharpdx?

Boxing Detected Objects in OpenCV

I am currently implementing a connected components algorithm and the last step of the algorithm requires me to enclose the objects I found in a box. I have attempted to enclose an object in a box and this is the result:
As you can see some of them seem to be enclosed in a box. Some of the lines of the box are not seen unless I stretch the windows of the imshow function's output and also some of them have color when I expected a line with a shade of gray.
My question is: Is the object really getting enclosed since I remember when I ran a similar code of mine into a different OS the lines with color are not see at all but are seen in my computer. Additionally, why are some of the lines in a different color given that I was expecting a shade of gray.
Mat src, src_gray;
Mat dst, detected_edges;
const char* window_name = "THRESHOLDED IMAGE";
/**
* #function connectedComponent
*/
static void connectedComponent(int, void*)
{
Mat test; //dummy
Mat sub;
int newObject = 0;
int zeroTest = 0, nonZero = 0;
int arr[5] = {0,0,0,0,0};
/// Reduce noise with a kernel 3x3
blur( src_gray,detected_edges, Size(3,3) ); //filtering out of noise
namedWindow("INITIAL", WINDOW_NORMAL);
imshow("INITIAL",detected_edges);
resizeWindow("INITIAL", 300, 300);
threshold(detected_edges, detected_edges, 0,255, THRESH_BINARY | THRESH_OTSU);
int** newSub = new int*[detected_edges.rows];
for(int i = 0; i < detected_edges.rows; i++)
newSub[i] = new int[detected_edges.cols];
for(int i = 0; i < detected_edges.rows; i++){
for(int j = 0; j < detected_edges.cols; j++){
newSub[i][j] = 0;
}
}
/*INITIAL MARKING LOOP*/
for(int i = 0; i < detected_edges.rows; i++){
for(int j = 0; j < detected_edges.cols; j++){
if(detected_edges.at<uchar>(i,j) == 0){
if(i-1 < 0 && j-1 < 0){
newObject = newObject + 1; //no values
newSub[i][j] = newObject;
}else if(i-1 >= 0 && j-1 < 0){
if(newSub[i-1][j] != 0){
newSub[i][j] = newSub[i-1][j]; //only up has value
}else{
newObject = newObject + 1; //no values
newSub[i][j] = newObject;
}
}else if(i-1 < 0 && j-1 >= 0){
if(newSub[i-1][j] != 0){
newSub[i][j] = newSub[i-1][j]; //only left has value
}else{
newObject = newObject + 1; //no values
newSub[i][j] = newObject;
}
}else{
if(newSub[i-1][j] == 0 && newSub[i][j-1] == 0){
newObject = newObject + 1; //no values
newSub[i][j] = newObject;
}else if(newSub[i-1][j] == newSub[i][j-1]){ //same value
newSub[i][j] = newSub[i-1][j];
}else if((newSub[i-1][j] != 0 && newSub[i][j-1] == 0)){
newSub[i][j] = newSub[i-1][j]; //only up has value
}else if(newSub[i-1][j] == 0 && newSub[i][j-1] != 0 ){
newSub[i][j] = newSub[i][j-1]; //only left has value
}else if(newSub[i-1][j] != newSub[i][j-1]){
newSub[i][j] = newSub[i-1][j]; //different values follow upper's value
}
}
}
}
}
int a = 1;
int maxRows = detected_edges.rows;
int maxCols = detected_edges.cols;
/*CONNECTING PIXELS RIGHT-BOTTOM*/
while(a < newObject){
int update = 0;
for(int i = 0; i < maxRows; i++){
for(int j = 0; j < maxCols; j++){
if(newSub[i][j] == a){
if(i+1 < maxRows && j+1 < maxCols){
if(newSub[i][j+1] > a){ //both points allowed
int value = newSub[i][j+1]; //get the value I need to replace
for(int h = 0; h < maxRows; h++){
for(int k = 0; k < maxCols; k++){
if(newSub[h][k] == value){ //replace all instances of that value
newSub[h][k] = a;
}
}
}
update = 1;
}
if(newSub[i+1][j] > a){ //both points allowed
int value = newSub[i+1][j]; //get the value I need to replace
for(int h = 0; h < maxRows; h++){
for(int k = 0; k < maxCols; k++){
if(newSub[h][k] == value){
newSub[h][k] = a; //replace all instances of that value
}
}
}
update = 1;
}
}else if(i+1 > maxRows && j+1 < maxCols){
if(newSub[i][j+1] > a){ //bottom is not allowed
int value = newSub[i][j+1]; //get the value I need to replace
for(int h = 0; h < maxRows; h++){
for(int k = 0; k < maxCols; k++){
if(newSub[h][k] == value){
newSub[h][k] = a; //replace all instances of that value
}
}
}
update = 1;
}
}else if(i+1 < maxRows && j+1 > maxCols){
if(newSub[i+1][j] > a){ //right is not allowed
int value = newSub[i+1][j]; //get the value I need to replace
for(int h = 0; h < maxRows; h++){
for(int k = 0; k < maxCols; k++){
if(newSub[h][k] == value){ //replace all instances of that value
newSub[h][k] = a;
}
}
}
update = 1;
}
}
}
}
}
a++;
}
/*CONNECTING PIXELS LEFT-TOP*/
a = newObject;
while(a > 0){
int update = 0;
for(int i = maxRows-1; i > 0; i--){
for(int j = maxCols-1; j > 0 ; j--){
if(newSub[i][j] == a){
if(i-1 >= 0 && j-1 >= 0){
if(newSub[i][j-1] > a){ //both points allowed
int value = newSub[i][j-1]; //get the value I need to replace
for(int h = 0; h < maxRows; h++){
for(int k = 0; k < maxCols; k++){
if(newSub[h][k] == value){
newSub[h][k] = a;
}
}
}
update = 1;
}
if(newSub[i-1][j] > a){
int value = newSub[i-1][j]; //get the value I need to replace
for(int h = 0; h < maxRows; h++){
for(int k = 0; k < maxCols; k++){
if(newSub[h][k] == value){ //replace all instances of that value
newSub[h][k] = a;
}
}
}
update = 1;
}
}else if(i-1 >= 0 && j-1 < 0){
if(newSub[i][j-1] > a){ //left is not allowed
int value = newSub[i][j-1]; //get the value I need to replace
for(int h = 0; h < maxRows; h++){
for(int k = 0; k < maxCols; k++){ //replace all instances of that value
if(newSub[h][k] == value){
newSub[h][k] = a;
}
}
}
update = 1;
}
}else if(i-1 < 0 && j-1 >= 0){
if(newSub[i-1][j] > a){ //top is not allowed
int value = newSub[i-1][j]; //get the value I need to replace
for(int h = 0; h < maxRows; h++){
for(int k = 0; k < maxCols; k++){ //replace all instances of that value
if(newSub[h][k] == value){
newSub[h][k] = a;
}
}
}
update = 1;
}
}
}
}
}
a--;
}
for(int i = 0; i < maxRows; i++){
for(int j = 0; j < maxCols; j++){
int check = 0;
if(newSub[i][j] != 0){
for(int k = 0; k < 5; k++){
if(newSub[i][j] == arr[k]){ //check if there is an instance of the value in the given array of values
check = 1;
break;
}
}
if(check == 0){
for(int r = 0; r < 5; r++){
if(arr[r] == 0){
arr[r] = newSub[i][j]; //if new value is found add to array
break;
}
}
}
}
}
}
/*
I HAVE AN ARRAY CONTAINING ALL VALUES
**/
src.copyTo( sub, detected_edges);
sub = Scalar::all(0);
/*SET AN INTENSITY FOR CORRESPONDING VALUES*/
int intensity = 50;
a = 0;
while(a < 5){
int update = 0;
for(int i = 0; i < maxRows; i++){
for(int j = 0; j < maxCols; j++){
if(newSub[i][j] == arr[a]){
sub.at<uchar>(i,j) = intensity;
}
}
}
a++;
intensity = intensity + 50;
}
a = 250;
/*GETTING MIN-MAX COORDINATES*/
while(a >= 50){
int setter = 0;
int minRow = 0;
int minCol = 0;
int maxRow = 0;
int maxCol = 0;
for(int i = 0; i < maxRows; i++){
for(int j = 0; j < maxCols; j++){
if(sub.at<uchar>(i,j) == a){
if(setter == 0){
minRow = i;
minCol = j;
maxRow = i;
maxCol = j;
setter = 1;
}else{
if(i <= minRow){
minRow = i;
}
else{
if(i > maxRow){
maxRow = i;
}
}
if(j <= minCol){
minCol = j;
}
else{
if(j > maxCol){
maxCol = j;
}
}
}
}
}
}
/*THIS IS WHERE I MAKE MY BOUNDING BOX*/
for(int i = minRow; i < maxRow; i++){
sub.at<uchar>(i,minCol) = 255; //set up the horizontal lines
sub.at<uchar>(i,maxCol) = 255;
}
for(int i = minCol; i < maxCol; i++){
sub.at<uchar>(minRow,i) = 255; //set up the vertical lines
sub.at<uchar>(maxRow,i) = 255;
}
a = a - 50;
}
dst = Scalar::all(0);
src.copyTo( dst, detected_edges);
imshow( window_name, dst );
namedWindow("FINAL", WINDOW_NORMAL);
imshow("FINAL",sub); //final output
resizeWindow("FINAL", 300, 300);
for(int i = 0; i < detected_edges.rows; i++)
delete[] newSub[i];
delete[] newSub;
}
/**
* #function main
*/
int main( int, char** argv )
{
/// Load an image
src = imread( argv[1] );
if( src.empty() )
{ return -1; }
/// Create a matrix of the same type and size as src (for dst)
dst.create( src.size(), src.type() );
/// Convert the image to grayscale
cvtColor( src, src_gray, COLOR_BGR2GRAY ); //grayscale for one channel for easy computation
/// Create a window
namedWindow( window_name, WINDOW_NORMAL );
resizeWindow(window_name, 300,300);
/// Show the image
connectedComponent(0, 0);
/// Wait until user exit program by pressing a key
waitKey(0);
return 0;
}

Blackberry Image processing(sketch effect and charcoal effect)

I am new to blackberry.
I am trying to convert normal image into sketch effect.I have code to do that in ANDROID.
I have tried to implement it in Blackberry but unable to got output.Here is android code and my blackberry code.
This is android code-
public class ConvolutionMatrix
{
public static final int SIZE = 3;
public double[][] Matrix;
public double Factor = 1;
public double Offset = 1;
public ConvolutionMatrix(int size) {
Matrix = new double[size][size];
}
public void setAll(double value) {
for (int x = 0; x < SIZE; ++x) {
for (int y = 0; y < SIZE; ++y) {
Matrix[x][y] = value;
}
}
}
public void applyConfig(double[][] config) {
for(int x = 0; x < SIZE; ++x) {
for(int y = 0; y < SIZE; ++y) {
Matrix[x][y] = config[x][y];
}
}
}
public static Bitmap computeConvolution3x3(Bitmap src, ConvolutionMatrix matrix) {
int width = src.getWidth();
int height = src.getHeight();
Bitmap result = Bitmap.createBitmap(width, height, src.getConfig());
int A, R, G, B;
int sumR, sumG, sumB;
int[][] pixels = new int[SIZE][SIZE];
for(int y = 0; y < height - 2; ++y) {
for(int x = 0; x < width - 2; ++x) {
// get pixel matrix
for(int i = 0; i < SIZE; ++i) {
for(int j = 0; j < SIZE; ++j) {
pixels[i][j] = src.getPixel(x + i, y + j);
}
}
// get alpha of center pixel
A = Color.alpha(pixels[1][1]);
// init color sum
sumR = sumG = sumB = 0;
// get sum of RGB on matrix
for(int i = 0; i < SIZE; ++i) {
for(int j = 0; j < SIZE; ++j) {
sumR += (Color.red(pixels[i][j]) * matrix.Matrix[i][j]);
sumG += (Color.green(pixels[i][j]) * matrix.Matrix[i][j]);
sumB += (Color.blue(pixels[i][j]) * matrix.Matrix[i][j]);
}
}
// get final Red
R = (int)(sumR / matrix.Factor + matrix.Offset);
if(R < 0) { R = 0; }
else if(R > 255) { R = 255; }
// get final Green
G = (int)(sumG / matrix.Factor + matrix.Offset);
if(G < 0) { G = 0; }
else if(G > 255) { G = 255; }
// get final Blue
B = (int)(sumB / matrix.Factor + matrix.Offset);
if(B < 0) { B = 0; }
else if(B > 255) { B = 255; }
// apply new pixel
result.setPixel(x + 1, y + 1, Color.argb(A, R, G, B));
}
}
// final image
return result;
}
}
and following is my Blackberry code that I have tried-
public ConvolutionMatrix(int size) {
Matrix = new double[size][size];
}
public void setAll(double value) {
for (int x = 0; x < SIZE; ++x) {
for (int y = 0; y < SIZE; ++y) {
Matrix[x][y] = value;
}
}
}
public void applyConfig(double[][] config) {
for(int x = 0; x < SIZE; ++x) {
for(int y = 0; y < SIZE; ++y) {
Matrix[x][y] = config[x][y];
}
}
}
public static Bitmap computeConvolution3x3(Bitmap src, ConvolutionMatrix matrix) {
int width = src.getWidth();
int height = src.getHeight();
int A, R, G, B;
int sumR, sumG, sumB;
int[] argb= new int[width*height];
int[][]newargb=new int[width][height];
src.getARGB(argb, 0, width, 0, 0, width, height);
for(int y=0;y<=height;y++)
{
for (int x=0;x<=width;x++)
{
System.out.println(""+x);
System.out.println(""+y);
newargb[y][x]=argb[width*y+x];
}
}
int[][] pixels = new int[SIZE][SIZE];
for(int y = 0; y < height - 2; ++y) {
for(int x = 0; x < width - 2; ++x) {
// get pixel matrix
for(int i = 0; i < SIZE; ++i) {
for(int j = 0; j < SIZE; ++j) {
pixels[i][j] = newargb[x + i][ y + j];
}
}
A=pixels[1][1];
sumR = sumG = sumB = 0;
for(int i = 0; i < SIZE; ++i) {
for(int j = 0; j < SIZE; ++j) {
A =pixels[i][j] >> 24;
R =pixels[i][j]>> 16 & 0xFF;
G =pixels[i][j] >> 8 & 0xFF;
B =pixels[i][j] & 0xFF;
sumR += (R * matrix.Matrix[i][j]);
sumG += (G * matrix.Matrix[i][j]);
sumB += (B * matrix.Matrix[i][j]);
}
}
// get final Red
R = (int)(sumR / matrix.Factor + matrix.Offset);
if(R < 0) { R = 0; }
else if(R > 255) { R = 255; }
// get final Green
G = (int)(sumG / matrix.Factor + matrix.Offset);
if(G < 0) { G = 0; }
else if(G > 255) { G = 255; }
// get final Blue
B = (int)(sumB / matrix.Factor + matrix.Offset);
if(B < 0) { B = 0; }
else if(B > 255) { B = 255; }
for(int i = 0; i < SIZE; ++i) {
for(int j = 0; j < SIZE; ++j) {
pixels[i][j]=(A << 24) | (R << 16) | (G << 8) | B;
newargb[x ][ y]=pixels[i][j];
}
}
}
}
for(int y=0;y<=height;y++)
{
for (int x=0;x<=width;x++)
{
argb[width*y+x]=newargb[y][x];
}
}
src.setARGB(argb, 0, width, 0, 0, width, height);
return src;
}
}
Common Code for both android and Blackberry-
public Bitmap EmbossImage(Bitmap src) {
System.out.println("In Emboss Effect Image method");
double[][] SharpConfig = new double[][] {
{ 0 , -1, 0 },
{ -1, 5, -1 },
{ 0 , -1, 0 }
};
ConvolutionMatrix convMatrix = new ConvolutionMatrix(3);
convMatrix.setAll(0);
convMatrix.applyConfig(SharpConfig);
convMatrix.Factor = 1;
convMatrix.offset=130;
return ConvolutionMatrix.computeConvolution3x3(src, convMatrix);
}
I have found the answer for my own question.I found convolution related code from this site:
android image processing.
See in the comments part on this link page.
This is android code.Just make it compatible it for blackberry by changing Color class methods.

Resources