Straighten contours OpenCV - opencv-python

Hello guys I would like to "straighten" some contours using opencv/python. Is there anyway to accomplish this?
I have attached two images:
in the current stage
and how I would like to see it .
Bounding boxes resolve the majority of the problem, but there are some exceptions that do not produce the desired outcome (see the top right contour in the image).
Thank you very much!
Current Contours
Squared Contours

def approximate_contours(image: np.ndarray, eps: float, color=(255, 255, 255)):
contours, _ = cv.findContours(image, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
image = cv.cvtColor(image, cv.COLOR_GRAY2BGR)
approx_contours = []
for cnt in contours:
epsilon = eps * cv.arcLength(cnt, True)
approx = cv.approxPolyDP(cnt, epsilon, True)
cv.drawContours(image, [approx], -1, color=color)
approx_contours.append(approx)
return image, approx_contours
def get_angle(pts: np.ndarray):
a = np.array([pts[0][0][0], pts[0][0][1]])
b = np.array([pts[1][0][0], pts[1][0][1]])
c = np.array([pts[2][0][0], pts[2][0][1]])
ba = a - b
bc = c - b
unit_vector_ba = ba / np.linalg.norm(ba)
unit_vector_bc = bc / np.linalg.norm(bc)
dot_product = np.dot(unit_vector_ba, unit_vector_bc)
angle_rad = np.arccos(dot_product)
angle_deg = degrees(angle_rad)
try:
int(angle_deg)
except Exception as e:
raise Exception("nan value detected")
return int(angle_deg)
def move_points(contour:np.ndarray, pts: np.ndarray, angle: int, ext: list, weight=1):
(ext_left, ext_right, ext_bot, ext_top) = ext
a = np.array([pts[0][0][0], pts[0][0][1]])
b = np.array([pts[1][0][0], pts[1][0][1]])
c = np.array([pts[2][0][0], pts[2][0][1]])
right_angle = False
if 45 < angle < 135:
right_angle = True
diff_x_ba = abs(b[0] - a[0])
diff_y_ba = abs(b[1] - a[1])
diff_x_bc = abs(b[0] - c[0])
diff_y_bc = abs(b[1] - c[1])
rap_ba = diff_x_ba / max(diff_y_ba, 1)
rap_bc = diff_x_bc / max(diff_y_bc, 1)
if rap_ba < rap_bc:
a[0] = int((a[0] * weight + b[0]) / (2 + weight - 1))
b[0] = a[0]
c[1] = int((c[1] + b[1]) / 2)
b[1] = c[1]
else:
c[0] = int((c[0] + b[0]) / 2)
b[0] = c[0]
a[1] = int((a[1] * weight + b[1]) / (2 + weight - 1))
b[1] = a[1]
else:
diff_x_ba = abs(b[0] - a[0])
diff_y_ba = abs(b[1] - a[1])
diff_x_bc = abs(b[0] - c[0])
diff_y_bc = abs(b[1] - c[1])
if (diff_x_ba + diff_x_bc) > (diff_y_ba + diff_y_bc):
a[1] = int((a[1] * weight + b[1] + c[1]) / (3 + weight - 1))
b[1] = a[1]
c[1] = a[1]
else:
a[0] = int((a[0] * weight + b[0] + c[0]) / (3 + weight - 1))
b[0] = a[0]
c[0] = a[0]
return a, b, c, right_angle
def straighten_contours(contours: list, image: np.ndarray, color=(255, 255, 255)):
image = cv.cvtColor(image, cv.COLOR_GRAY2BGR)
for cnt in contours:
idx = 0
ext_left = cnt[cnt[:, :, 0].argmin()][0]
ext_right = cnt[cnt[:, :, 0].argmax()][0]
ext_top = cnt[cnt[:, :, 1].argmin()][0]
ext_bot = cnt[cnt[:, :, 1].argmax()][0]
while idx != int(cnt.size / 2):
try:
angle = get_angle(cnt[idx:idx + 3])
except Exception:
idx += 1
continue
(a, b, c, right_angle) = move_points(cnt, cnt[idx:idx + 3], angle, [ext_left, ext_right, ext_bot, ext_top])
cnt[idx][0] = a
cnt[idx + 1][0] = b
cnt[idx + 2][0] = c
idx += 1
if not right_angle:
idx -= 1
cnt = np.delete(cnt, (idx + 1), 0)
if idx == 1:
cnt = np.append(cnt, cnt[:2], axis=0)
cnt = np.delete(cnt, [0, 1], 0)
cv.drawContours(image, [cnt], -1, color=color)
return image
I managed to do some workarounds. The straighten contours function is applied onto the approximate_contours result (the first image in the question). Is not as good as I would have wanted it to be but it works.

Related

whats the use of commented line in my code please explain in details

#the problem is why i used GCD (find the max point of a straight line). I can find out the slope by #doing m = (y2-y1) / (x2-x1), then whats the purpose to use gcd?
def lineThroughPoints(points):
maxNumberOfPointsOnLine = 1
for idx1, p1 in enumerate(points):
slopes = {}
for idx2 in range(idx1 + 1, len(points)):
p2 = points[idx2]
rise, run = getSlopeOfLineBetweenPoints(p1, p2)
slopeKey = createHashableKeyForRational(rise, run)
if slopeKey not in slopes:
slopes[slopeKey] = 1
slopes[slopeKey] += 1
maxNumberOfPointsOnLine = max(maxNumberOfPointsOnLine, max(slopes.values(), default=0))
return maxNumberOfPointsOnLine
def getSlopeOfLineBetweenPoints(p1, p2):
p1x, p1y = p1
p2x, p2y = p2
slope = [1, 0] # slope of a vertical line
if p1x != p2x: # if line is not vertical
xDiff = p1x - p2x
yDiff = p1y - p2y
gcd = getGreatestCommonDivisor(abs(xDiff), abs(yDiff))
xDiff = xDiff // gcd
yDiff = yDiff // gcd
if xDiff < 0:
xDiff *= -1
yDiff *= -1
slope = [yDiff, xDiff]
return slope
def createHashableKeyForRational(numerator, denominator):
return str(numerator) + ":" + str(denominator)
def getGreatestCommonDivisor(num1, num2):
a = num1
b = num2
while True:
if a == 0:
return b
if b == 0:
return a
a, b = b, a % b
points = [[1, 1],[2, 2],[3, 3],[0, 4],[-2, 6],[4, 0],[2, 1]]
print(lineThroughPoints(points))

Sum of rectangles in Matlab

I have a code which doesnt work the way I want to. The problem is i need a sum of all rctangles from a picture as below.
My code:
imH = size(I, 1);
imW = size(I, 2);
windowWidth = 30;
windowHeight = 30;
step = 1;
for r = 1:step:imH - windowHeight + 1
for c = 1:step:imW - windowWidth + 1
Win = I(r:r + windowHeight - 1, c:c + windowWidth - 1, :);
post =[c r windowHeight windowWidth];
I think I lack sum here
%stop = waitforbuttonpress;
subplot(121); imshow(I); title 'Image';
hold on;
rectangle('Position', pos, 'EdgeColor', 'r');
hold off;
subplot (122); imshow(W); title 'ooo';
drawnow;
pause(0.0000001);
end
end
Everything works great but I need to sum separately every rectangle values
You only need to add & in the 1st and 2nd rgb intervals as below:
matchNh = (R > 45 & R < 180) & (G > 50 & G < 185) & (B > 160 & B < 215);
matchNd = (R > 40 & R < 115) & (G > 6 & G < 80) & (B > 10 & B < 75);
Then you are doing right to count the nonzero pixels i.e.
Nh = nnz(matchNh);
Nd = nnz(matchNd);
If you want to use for more than one image , then you can use another for loop outside the two for loops e.g.
imgnames = dir('*.jpg'); % get list of jpg images in current directory
NN = length(imgnames)
%sliding window size
windowWidth = 64;
windowHeight = 64;
%step
step = 64;
Nh = 0;
Nd = 0;
for ii = 1 : NN
I = imread(imgnames(ii).name);
% your code i.e. two for loops as you have written above
imH = size(I, 1);
imW = size(I, 2);
for r = 1:step:imH - windowHeight + 1
for c = 1:step:imW - windowWidth + 1
%sliding window value
W = I(r:r + windowHeight - 1, c:c + windowWidth - 1, :);
pos =[c r windowHeight windowWidth];
R = W(:,:,1);
G = W(:,:,2);
B = W(:,:,3);
% RGB intervals for every sliding window
matchNh = (R > 45 & R < 180) & ...
(G > 50 & G < 185) & ...
(B > 160 & B < 215);
matchNd = (R > 40 & R < 115) & ...
(G > 6 & G < 80) & ...
(B > 10 & B < 75);
Nh = Nh + nnz(matchNh);
Nd = Nd + nnz(matchNd);
end
end
PIc = Nd / (Nh + Nd)
end

neural network error is a matrix

i recently made a simple neural network, and i found that the error is a matrix when its supposed to be a single number, which causes the output to change from a simple 4*1 matrix to a 4*20 matrix, can someone pleas help me figure out how i have to redefine the error to change the l5_error into a 4*1 matrix while preserving the accuracy of the network
<import numpy as np
def nonlin(x, deriv=False):
if (deriv == True):
return (x * (1 - x))
return 1 / (1 + np.exp(-x))
X = np.array([[1,1,0],
[0,1,1],
[0,0,1],
[1, 0, 0]])
y = np.array([[0],
[1],
[0],
[1]])
np.random.seed(1)
syn0 = 2 * np.random.random((len(X[1]), 100)) - 1
syn1 = 2 * np.random.random((100, 80)) - 1
syn2 = 2 * np.random.random((80, 60)) - 1
syn3 = 2 * np.random.random((60, 40)) - 1
syn4 = 2 * np.random.random((40, 20)) - 1
syn5 = 2 * np.random.random((20, 1)) - 1
#the layers are only defined here so i can see the dimensions of the error
l0 = X
l1 = nonlin(np.dot(l0, syn0))
l2 = nonlin(np.dot(l1, syn1))
l3 = nonlin(np.dot(l2, syn2))
l4 = nonlin(np.dot(l3, syn3))
l5 = nonlin(np.dot(l4, syn4))
l5_error = y - l5
print('beggining', l5_error, 'ending')
for i in range(1000):
l0 = X
l1 = nonlin(np.dot(l0, syn0))
l2 = nonlin(np.dot(l1, syn1))
l3 = nonlin(np.dot(l2, syn2))
l4 = nonlin(np.dot(l3, syn3))
l5 = nonlin(np.dot(l4, syn4))
l5_error = y - l5
if (i % 10) == 0:
print( "Error: " + str(np.mean(np.abs(l5_error))))
print(l5_error, nonlin(l5, deriv=True))
l5_delta = l5_error * nonlin(l5, deriv=True)
l4_error = l5_delta.dot(syn4.T)
l4_delta = l4_error * nonlin(l4, deriv=True)
l3_error = l4_delta.dot(syn3.T)
l3_delta = l3_error * nonlin(l3, deriv=True)
l2_error = l3_delta.dot(syn2.T)
l2_delta = l2_error * nonlin(l2, deriv=True)
l1_error = l2_delta.dot(syn1.T)
l1_delta = l1_error * nonlin(l1, deriv=True)
#syn5 += l5.T.dot(l6_delta)
syn4 += l4.T.dot(l5_delta)
syn3 += l3.T.dot(l4_delta)
syn2 += l2.T.dot(l3_delta)
syn1 += l1.T.dot(l2_delta)
syn0 += l0.T.dot(l1_delta)
print ("Output after training")
print (l5)
You've got a mistake in the definition of l5_error, it should be
l5_error = np.linalg.norm(y-l5)
This same issue occurs some of the other error variables; simply add a call np.linalg.norm to each.

Matlab: resize with custom interpolation kernel Mitchell-Netravali

I have seen that there was an interest in custom interpolation kernels for resize (MATLAB imresize with a custom interpolation kernel). Did anyone implemented the parametric Mitchell-Netravali kernel [1] that is used as default in ImageMagick and is willing to share the Matlab code? Thank you very much!
[1] http://developer.download.nvidia.com/books/HTML/gpugems/gpugems_ch24.html
// Mitchell Netravali Reconstruction Filter
// B = 0 C = 0 - Hermite B-Spline interpolator
// B = 1, C = 0 - cubic B-spline
// B = 0, C = 1/2 - Catmull-Rom spline
// B = 1/3, C = 1/3 - recommended
float MitchellNetravali(float x, float B, float C)
{
float ax = fabs(x);
if (ax < 1) {
return ((12 - 9 * B - 6 * C) * ax * ax * ax +
(-18 + 12 * B + 6 * C) * ax * ax + (6 - 2 * B)) / 6;
} else if ((ax >= 1) && (ax < 2)) {
return ((-B - 6 * C) * ax * ax * ax +
(6 * B + 30 * C) * ax * ax + (-12 * B - 48 * C) *
ax + (8 * B + 24 * C)) / 6;
} else {
return 0;
}
}
Here I got another approach with vectorization; according to my tests with upscaling (1000x1000 -> 3000x3000) this is faster than the standard bicubic even with a large Mitchell radius = 6:
function [outputs] = Mitchell_vect(x,M_B,M_C)
outputs= zeros(size(x,1),size(x,2));
ax = abs(x);
temp = ((12-9*M_B-6*M_C) .* ax.^3 + (-18+12*M_B+6*M_C) .* ax.^2 + (6-2*M_B))./6;
temp2 = ((-M_B-6*M_C) .* ax.^3 + (6*M_B+30*M_C) .* ax.^2 + (-12*M_B-48*M_C) .* ax + (8*M_B + 24*M_C))./6;
index = find(ax<1);
outputs(index)=temp(index);
index = find(ax>=1 & ax<2);
outputs(index)=temp2(index);
end
I got the following proposal for the Mitchel kernel called by imresize with the parameters B and C and a kernel radius using for-loops (and preallocation):
img_resize = imresize(img, [h w], {#(x)Mitchell(x,B,C),radius});
function [outputs] = Mitchell(x,B,C)
outputs= zeros(size(x,1),size(x,2));
for i = 1 : size(x,1)
for j = 1 : size(x,2)
ax = abs(x(i,j));
if ax < 1
outputs(i,j) = ((12-9*B-6*C) * ax^3 + (-18+12*B+6*C) * ax^2 + (6-2*B))/6;
elseif (ax >= 1) && (ax < 2)
outputs(i,j) = ((-B-6*C) * ax^3 + (6*B+30*C) * ax^2 + (-12*B-48*C) * ax + (8*B + 24*C))/6;
else
outputs(i,j) = 0;
end
end
end
end

Having trouble creating faces on triangle mesh JavaFX 8

I'm trying to create a Toroid mesh, however I cant create the faces properly...
here is my code:
public static Group createToroidMesh(float radius, float tRadius, int tDivs, int rDivs) {
final Group root = new Group();
int numVerts = tDivs * rDivs;
float[] points = new float[numVerts * POINT_SIZE],
texCoords = new float[numVerts * TEXCOORD_SIZE];
int[] faces = new int[numVerts * FACE_SIZE],
smoothingGroups;
int pointIndex = 0, texIndex = 0, faceIndex = 0, smoothIndex = 0;
float tFrac = 1.0f / tDivs;
float rFrac = 1.0f / rDivs;
float x, y, z;
int p0 = 0, p1 = 0, p2 = 0, p3 = 0, t0 = 0, t1 = 0, t2 = 0, t3 = 0;
// create points
for (int vertIndex = 0; vertIndex < tDivs; vertIndex++) {
float radian = tFrac * vertIndex * 2.0f * 3.141592653589793f;
for (int crossSectionIndex = 0; crossSectionIndex < rDivs; crossSectionIndex++) {
float localRadian = rFrac * crossSectionIndex * 2.0f * 3.141592653589793f;
points[pointIndex] = x = (radius + tRadius * ((float) Math.cos(radian))) * ((float) Math.cos(localRadian));
points[pointIndex + 1] = y = (radius + tRadius * ((float) Math.cos(radian))) * ((float) Math.sin(localRadian));
points[pointIndex + 2] = z = (tRadius * (float) Math.sin(radian));
pointIndex += 3;
float r = crossSectionIndex < tDivs ? tFrac * crossSectionIndex * 2.0F * 3.141592653589793f : 0.0f;
texCoords[texIndex] = (0.5F + (float) (Math.sin(r) * 0.5D));;
texCoords[texIndex + 1] = ((float) (Math.cos(r) * 0.5D) + 0.5F);
texIndex += 2;
}
}
//create faces
for (int y1 = 0; y1 < tDivs - 1 ; y1++) {
float radian = tFrac * y1 * 2.0f * 3.141592653589793f;
for (int x1 = 0; x1 < rDivs - 1; x1++) {
float localRadian = rFrac * x1 * 2.0f * 3.141592653589793f;
p0 = y1 * rDivs + x1;
p1 = p0 + 1;
p2 = p0 + rDivs;
p3 = p2 + 1;
t0 = y1 * rDivs + x1;
t1 = t0 + 1;
t2 = t0 + rDivs;
t3 = t1 + 1;
try {
faces[faceIndex] = (p2);
faces[faceIndex + 1] = (t3);
faces[faceIndex + 2] = (p0);
faces[faceIndex + 3] = (t2);
faces[faceIndex + 4] = (p1);
faces[faceIndex + 5] = (t0);
faceIndex += FACE_SIZE;
faces[faceIndex] = (p2);
faces[faceIndex + 1] = (t3);
faces[faceIndex + 2] = (p1);
faces[faceIndex + 3] = (t0);
faces[faceIndex + 4] = (p3);
faces[faceIndex + 5] = (t1);
//faceIndex += FACE_SIZE;
} catch (Exception e) {
break;
}
}
}
TriangleMesh localTriangleMesh = new TriangleMesh();
localTriangleMesh.getPoints().setAll(points);
localTriangleMesh.getTexCoords().setAll(texCoords);
localTriangleMesh.getFaces().setAll(faces);
MeshView view = new MeshView(localTriangleMesh);
view.setMaterial(new PhongMaterial(Color.BLUEVIOLET));
view.setCullFace(CullFace.BACK);
root.getChildren().clear();
root.getChildren().add(view);
//return localTriangleMesh;
System.out.println("objs in group: " + root.getChildren().size()
+ ", \nnum of points in array: " + points.length / POINT_SIZE
+ ", \nnum TexCoords: " + texCoords.length / TEXCOORD_SIZE
+ ", \nface count: " + faces.length / FACE_SIZE);
root.setRotationAxis(Rotate.X_AXIS);
root.setRotate(90);
return root;
}
and here is the result:
can someone help me iterate through this a little better?
my constructor for the mesh is : Group verts = MeshUtils.createToroidMesh(100,15,4,4);
OK, I figured the problem out... The problem was in my faces loop. It was adding values outside the range of points, and texCoords, here is the corrected loop:
//create faces
for (int point = 0; point < (tubeDivisions) ; point++) {
for (int crossSection = 0; crossSection < (radiusDivisions) ; crossSection++) {
p0 = point * radiusDivisions + crossSection;
p1 = p0 >= 0 ? p0 + 1 : p0 - (radiusDivisions);
p1 = p1 % (radiusDivisions) != 0 ? p0 + 1 : p0 - (radiusDivisions - 1);
p2 = (p0 + radiusDivisions) < ((tubeDivisions * radiusDivisions)) ? p0 + radiusDivisions : p0 - (tubeDivisions * radiusDivisions) + radiusDivisions ;
p3 = p2 < ((tubeDivisions * radiusDivisions) - 1) ? p2 + 1 : p2 - (tubeDivisions * radiusDivisions) + 1;
p3 = p3 % (radiusDivisions) != 0 ? p2 + 1 : p2 - (radiusDivisions - 1);
t0 = point * (radiusDivisions) + crossSection;
t1 = t0 >= 0 ? t0 + 1 : t0 - (radiusDivisions);
t1 = t1 % (radiusDivisions) != 0 ? t0 + 1 : t0 - (radiusDivisions - 1);
t2 = (t0 + radiusDivisions) < ((tubeDivisions * radiusDivisions)) ? t0 + radiusDivisions : t0 - (tubeDivisions * radiusDivisions) + radiusDivisions ;
t3 = t2 < ((tubeDivisions * radiusDivisions) - 1) ? t2 + 1 : t2 - (tubeDivisions * radiusDivisions) + 1;
t3 = t3 % (radiusDivisions) != 0 ? t2 + 1 : t2 - (radiusDivisions - 1);
try {
faces[faceIndex] = (p2);
faces[faceIndex + 1] = (t3);
faces[faceIndex + 2] = (p0);
faces[faceIndex + 3] = (t2);
faces[faceIndex + 4] = (p1);
faces[faceIndex + 5] = (t0);
faceIndex += FACE_SIZE;
faces[faceIndex] = (p2);
faces[faceIndex + 1] = (t3);
faces[faceIndex + 2] = (p1);
faces[faceIndex + 3] = (t0);
faces[faceIndex + 4] = (p3);
faces[faceIndex + 5] = (t1);
faceIndex += FACE_SIZE;
} catch (Exception e) {
e.printStackTrace();
}
//System.out.println(" :: " +p0 + " : " + p1 + " : " + p2 + " : " + p3);
}
}
and the results: (square toroid)
(Round toroid)
Hope this can help if you struggle as well!
Please Note I did not assign UV textures as they should have been(if using Image material) since Only Color is used. TexCoords can be anything (0 - 1.0) if only using colors