Shrinking images using recursion incorrect positioning - c++

I am writing code that takes an image and creates subimages within the original image. I am doing this recursively with a rectangle class that keeps track of starting and stopping positions of the subimage. After the 3rd recursive call is where i run into trouble. The new subimages are being placed in the incorrect spots. They should be shrinking as they approach the top right corner of the image. I have run through the debugger and watched the start and stop positions change with each call and they reflect movement toward the top right corner. The only place I think the error could be is where I create a new rectangle called rRight to be put into the recursive call.
int main()
{
CImage original("test256.gif");
Rectangle rPrev(0, 0, original.getRows(), original.getCols());
Rectangle r(0, 0, (original.getRows() / 2), (original.getCols() / 2));
CImage final = fractal(original, r, rPrev);
final.output("output.gif");
system("PAUSE");
return 0;
}
CImage fractal(CImage &origin, Rectangle &r, Rectangle &rPrev)
{
if (r.getX2() - r.getX1() > 0 && r.getY2() - r.getY1() > 0)
{
drawTopLeft(origin, r, rPrev);
Rectangle rRight(0, r.getY2(), (r.getX2() / 2), (r.getY2() + ((r.getY2() - r.getY1()) / 2)));
fractal(origin, rRight, r);
}
return origin;
}
void drawTopLeft(CImage &origin, Rectangle &r, Rectangle &rPrev)
{
for (int row = rPrev.getX1(); row < rPrev.getX2(); row += 2)
{
for (int col = rPrev.getY1(); col < rPrev.getY2(); col += 2)
{
pixel p1 = origin.getPixel(row, col);
pixel p2 = origin.getPixel(row + 1, col);
pixel p3 = origin.getPixel(row, col + 1);
pixel p4 = origin.getPixel(row + 1, col + 1);
int avgRed = (p1.red + p2.red + p3.red + p4.red) / 4;
int avgGreen = (p1.green + p2.green + p3.green + p4.green) / 4;
int avgBlue = (p1.blue + p2.blue + p3.blue + p4.blue) / 4;
origin.setPixel((row / 2) + r.getX1(), (col / 2) + r.getY1(), avgRed, avgGreen, avgBlue);
}
}
}

Related

OpenCV zooming in on Mat image without the window border changing c++

I have a window Mat gestures containing an image, I want to zoom in every pixel in the window but keep the border the same size. I have tried resize() but it's resizing the border as well.
For better explanation, I don't want the border that is in the green box to be resized as well as the whole border, but I need the image inside the border to be resized. How can I achieve this?
Set a ROI of the image excluding the border. If you already know the thickness, simply assign a new img from it. Then you can resize and draw cv::rectangle with the thickness of original image.
Following code snippet may not compile since I don't see a reproducible code.
cv::Mat img = cv::imread(...);
const int thick = 3;
const cv::Rect roi(thick, thick, img.width()-2*thick, img.height()-2*thick);
cv::Mat img_roi = img(roi);
cv::resize(...); // resize img_roi
cv::rectangle(...); // draw new border on img_roi, you need to pass a cv::Scalar value from img.at(0, 0) for the color of it.
However, I'm expecting a better idea from someone else.
The basic idea is deciding the scale changed every time on mouse wheel. After you get the current scale (v.s. origin image), you then can get the position and length of rectangle on scaled image.
In my github,checking OnMouseWheel () and RefreshSrcView () in Fastest_Image_Pattern_Matching/ELCVMatchTool/ELCVMatchToolDlg.cpp may give what you want.
Besides, if you only want to use opencv window without MFC framework or other frameworks, check this (pure OpenCV version)
Effect:
Part of the code:
BOOL CELCVMatchToolDlg::OnMouseWheel (UINT nFlags, short zDelta, CPoint pt)
{
POINT pointCursor;
GetCursorPos (&pointCursor);
ScreenToClient (&pointCursor);
// TODO: 在此加入您的訊息處理常式程式碼和 (或) 呼叫預設值
if (zDelta > 0)
{
if (m_iScaleTimes == MAX_SCALE_TIMES)
return TRUE;
else
m_iScaleTimes++;
}
if (zDelta < 0)
{
if (m_iScaleTimes == MIN_SCALE_TIMES)
return TRUE;
else
m_iScaleTimes--;
}
CRect rect;
//GetWindowRect (rect);
GetDlgItem (IDC_STATIC_SRC_VIEW)->GetWindowRect (rect);//重要
if (m_iScaleTimes == 0)
g_dCompensationX = g_dCompensationY = 0;
int iMouseOffsetX = pt.x - (rect.left + 1);
int iMouseOffsetY = pt.y - (rect.top + 1);
double dPixelX = (m_hScrollBar.GetScrollPos () + iMouseOffsetX + g_dCompensationX) / m_dNewScale;
double dPixelY = (m_vScrollBar.GetScrollPos () + iMouseOffsetY + g_dCompensationY) / m_dNewScale;
m_dNewScale = m_dSrcScale * pow (SCALE_RATIO, m_iScaleTimes);
if (m_iScaleTimes != 0)
{
int iWidth = m_matSrc.cols;
int iHeight = m_matSrc.rows;
m_hScrollBar.SetScrollRange (0, int (m_dNewScale * iWidth - m_dSrcScale * iWidth) - 1 + BAR_SIZE);
m_vScrollBar.SetScrollRange (0, int (m_dNewScale * iHeight - m_dSrcScale * iHeight) - 1 + BAR_SIZE);
int iBarPosX = int (dPixelX * m_dNewScale - iMouseOffsetX + 0.5);
m_hScrollBar.SetScrollPos (iBarPosX);
m_hScrollBar.ShowWindow (SW_SHOW);
g_dCompensationX = -iBarPosX + (dPixelX * m_dNewScale - iMouseOffsetX);
int iBarPosY = int (dPixelY * m_dNewScale - iMouseOffsetY + 0.5);
m_vScrollBar.SetScrollPos (iBarPosY);
m_vScrollBar.ShowWindow (SW_SHOW);
g_dCompensationY = -iBarPosY + (dPixelY * m_dNewScale - iMouseOffsetY);
//滑塊大小
SCROLLINFO infoH;
infoH.cbSize = sizeof (SCROLLINFO);
infoH.fMask = SIF_PAGE;
infoH.nPage = BAR_SIZE;
m_hScrollBar.SetScrollInfo (&infoH);
SCROLLINFO infoV;
infoV.cbSize = sizeof (SCROLLINFO);
infoV.fMask = SIF_PAGE;
infoV.nPage = BAR_SIZE;
m_vScrollBar.SetScrollInfo (&infoV);
//滑塊大小
}
else
{
m_hScrollBar.SetScrollPos (0);
m_hScrollBar.ShowWindow (SW_HIDE);
m_vScrollBar.SetScrollPos (0);
m_vScrollBar.ShowWindow (SW_HIDE);
}
RefreshSrcView ();
return CDialogEx::OnMouseWheel (nFlags, zDelta, pt);
}

Create board for Catan with SFML

I want to create the board for Catan game with SFML, and all i need is 19 shapes(hexagons) for each of them i can take all the 6 corners and the 6 sides, to build cities or roads.
For shapes i make this:
std::vector<sf::CircleShape> shape(19);
int n = 0;
int shape_y = 100;
for (size_t index = 0; index < shape.size(); index++) {
if (index < 3) {
sf::CircleShape sh(80, 6);
sh.setPosition(200 + n, shape_y);
sh.setFillColor(sf::Color::Magenta);
shape[index] = sh;
n += 140;
}
if (index == 3)
n = 0;
if (index < 7 && index >= 3) {
sf::CircleShape sh(80, 6);
sh.setPosition(130 + n, shape_y + 120);
sh.setFillColor(sf::Color::Blue);
shape[index] = sh;
n += 140;
}
if (index == 7)
n = 0;
if (index >= 7 && index < 12) {
sf::CircleShape sh(80, 6);
sh.setPosition(60 + n, shape_y + 240);
sh.setFillColor(sf::Color::Red);
shape[index] = sh;
n += 140;
}
if (index == 12)
n = 0;
if (index >= 12 && index < 16) {
sf::CircleShape sh(80, 6);
sh.setPosition(130 + n, shape_y + 360);
sh.setFillColor(sf::Color::Green);
shape[index] = sh;
n += 140;
}
if (index == 16)
n = 0;
if (index >= 16 && index < 19) {
sf::CircleShape sh(80, 6);
sh.setPosition(200 + n, shape_y + 480);
sh.setFillColor(sf::Color::Yellow);
shape[index] = sh;
n += 140;
}
}
This looks like this:
But how i get the corners and the sides from shapes? If i use getPoint(0) for corner, it don't draw the point where its belongs.
If this is not a good idea, what can i use for this problem?
I did that mechanism long time ago, a simple way to achieve that.
My approach was to represent each hexagon as a circle. The drawn hexagon was embedded into that circle. To check if the mouse was over a corner or a side, I did a simple check:
If the point was inside 3 circles simultaneously, it was a corner (the meeting corner of those 3 hexagons)
If the point was inside 2 circles, it was a side.
If the point was inside 1 circle, it was a whole hexagon
Proof of concept:
The blue hexagons conform the proper board, each of these have a red circle (larger than the hexagon itself).
The green hexagons are out of the board (they aren't part of the game board) and they help to know if mouse is over sides or corners of the outter hexagons.
Full code is in my Github repository, but is quite old and may be out of date

Manipulating sfml Vertex Array

I am doing research on the sfml Vertex Array functions.Based on this tutorial I've been introduced to a basic implementation and am wanting to add to it. Unfortunately I am relatively new at OOP and would appreciate any help adding to this.
The output generates a checkerboard like pattern using a sprite grid.
My goal is to connect the grid-floor tiles using a pathfinding algorithm(recursive bactracker) to generate a path.
the rest of this part is instantiated in the main.cpp:
//load the texture for our background vertex array
Texture textureBackground;
textureBackground.loadFromFile("graphics/background_sheet.png");
once in the game loop as:
//pass the vertex array by reference to the createBackground function
int tileSize = createBackground(background, arena);
and finally in the draw scene:
window.draw(background, &textureBackground);
#include "stdafx.h"
#include <SFML/Graphics.hpp>
#include "zArena.h"
int createBackground(VertexArray& rVA, IntRect arena)
{
// Anything we do to rVA we are actually doing to background (in the main function)
// How big is each tile/texture
const int TILE_SIZE = 50;
const int TILE_TYPES = 3;
const int VERTS_IN_QUAD = 4;
int worldWidth = arena.width / TILE_SIZE;
int worldHeight = arena.height / TILE_SIZE;
// What type of primitive are we using?
rVA.setPrimitiveType(Quads);
// Set the size of the vertex array
rVA.resize(worldWidth * worldHeight * VERTS_IN_QUAD);
// Start at the beginning of the vertex array
int currentVertex = 0;
for (int w = 0; w < worldWidth; w++)
{
for (int h = 0; h < worldHeight; h++)
{
// Position each vertex in the current quad
rVA[currentVertex + 0].position = Vector2f(w * TILE_SIZE, h * TILE_SIZE);
rVA[currentVertex + 1].position = Vector2f((w * TILE_SIZE) + TILE_SIZE, h * TILE_SIZE);
rVA[currentVertex + 2].position = Vector2f((w * TILE_SIZE) + TILE_SIZE, (h * TILE_SIZE) + TILE_SIZE);
rVA[currentVertex + 3].position = Vector2f((w * TILE_SIZE), (h * TILE_SIZE) + TILE_SIZE);
// Define the position in the Texture to draw for current quad
// Either mud, stone, grass or wall
//if (h == 0 || h == worldHeight - 1 || w == 0 || w == worldWidth - 1)
if ((h % 2 !=0)&& (w % 2 != 0))
{
// Use the wall texture
rVA[currentVertex + 0].texCoords = Vector2f(0, 0 + TILE_TYPES * TILE_SIZE);
rVA[currentVertex + 1].texCoords = Vector2f(TILE_SIZE, 0 + TILE_TYPES * TILE_SIZE);
rVA[currentVertex + 2].texCoords = Vector2f(TILE_SIZE, TILE_SIZE + TILE_TYPES * TILE_SIZE);
rVA[currentVertex + 3].texCoords = Vector2f(0, TILE_SIZE + TILE_TYPES * TILE_SIZE);
}
else
{
// Use a random floor texture
srand((int)time(0) + h * w - h);
int mOrG = (rand() % TILE_TYPES);
int verticalOffset = mOrG * TILE_SIZE;
//int verticalOffset = 0;
rVA[currentVertex + 0].texCoords = Vector2f(0, 0 + verticalOffset);
rVA[currentVertex + 1].texCoords = Vector2f(TILE_SIZE, 0 + verticalOffset);
rVA[currentVertex + 2].texCoords = Vector2f(TILE_SIZE, TILE_SIZE + verticalOffset);
rVA[currentVertex + 3].texCoords = Vector2f(0, TILE_SIZE + verticalOffset);
}
// Position ready for the next for vertices
currentVertex = currentVertex + VERTS_IN_QUAD;
}
}
return TILE_SIZE;
}
As far as i see, there you're generating your tiles on the fly. If you want to create something like a walkable space, you should generate your tile map first, and then draw it based on the content generated.
Maybe overkilling your question, there are several ways to generate random maps satisfying specific constraints.
When you have the choice done, then you can simply draw as you do, but instead of
// Use a random floor texture
srand((int)time(0) + h * w - h);
int mOrG = (rand() % TILE_TYPES);
int verticalOffset = mOrG * TILE_SIZE;
should have something like
// Select texture rect based on generated tilemap
int mOrG = tilemap[w][h]; // Or tilemap[h * worldWidth + w] if you do it as unidimensional array
int verticalOffset = mOrG * TILE_SIZE;
With this approach you must pass tilemap to your render method or, even better, create a TileMap class overriding draw() method

Overlay on 4 channel image

I have a image with 4 channels that i need to overlay it over a bunch of pictures. Over the pictures with 3 channels, the overlaying works great, but over the pictures that have an alpha channel, the background of the picture changes to black.
Original picture: http://img.blog.csdn.net/20130610074054484
Overlayed picture: http://imgur.com/mlVAN0A
This is the code that does the overlaying:
void overlayImage(const cv::Mat &background, const cv::Mat &foreground,
cv::Mat &output, cv::Point2i location)
{
background.copyTo(output);
for(int y = std::max(location.y , 0); y < background.rows; ++y)
{
int fY = y - location.y;
if(fY >= foreground.rows)
break;
for(int x = std::max(location.x, 0); x < background.cols; ++x)
{
int fX = x - location.x;
if(fX >= foreground.cols)
break;
double opacity = ((double)foreground.data[fY * foreground.step + fX * foreground.channels() + 3]) / 255.;
for(int c = 0; opacity > 0 && c < output.channels(); ++c)
{
unsigned char foregroundPx = foreground.data[fY * foreground.step + fX * foreground.channels() + c];
unsigned char backgroundPx = background.data[y * background.step + x * background.channels() + c];
output.data[y*output.step + output.channels()*x + c] =
backgroundPx * (1.-opacity) + foregroundPx * opacity;
}
}
}
}
This is because you use 1-opacity for the background image. If the opacity of the forground image is 0, the opacity of your backgroundpixel will be 1 instead of 0 which it is before.
You have to calc the result opacity fpr both images which can be 0 for both too.
Claus

SFML mouse position and collision loading from file

Okay so I have two problems. First off I have made a square that is locked to a grid the same size as my tiles. This is what will be used for changing tiles. It works fine except for when I start scrolling. I know why it is. It's because the mouse position is relative to the window, not the map. I was wondering if there was a way I could code the squares to follow my mouse even when I scroll.
Current code:
if (Event.type == sf::Event::MouseMoved)
{
rect.setFillColor(sf::Color(255, 0, 255));
rect.setSize(sf::Vector2f(BLOCKSIZE, BLOCKSIZE));
int x_offset = (Window.getView().getCenter().x - Window.getSize().x /2);
int y_offset = (Window.getView().getCenter().y - Window.getSize().y /2);
rect.setPosition(((sf::Mouse::getPosition(Window).x/32 *32) + (x_offset/32 *32)), ((sf::Mouse::getPosition(Window).y/32 * 32) + (y_offset/32 * 32)));
std::cout << "Mouse position: x:" << ((sf::Mouse::getPosition(Window).x/32 *32) + (x_offset/32 *32)) << " y:" << ((sf::Mouse::getPosition(Window).y/32 * 32) + (y_offset/32 * 32)) << ")\n\n";
}
Next problem is loading collision.
Code:
for(int i = 0; i < CollisionVector.size(); i++)
{
//Loop through the height of the MapVector
for(int j = 0; j < CollisionVector[i].size(); j++)
{
sf::RectangleShape rect;
//If the stored number is 1
if(CollisionVector[i][j] == 1)
{
rect.setFillColor(sf::Color(255, 0, 255));
rect.setSize(sf::Vector2f(BLOCKSIZE, BLOCKSIZE));
//Set the position of the rectangle
rect.setPosition(j * BLOCKSIZE, i * BLOCKSIZE);
}
//Draw the rectangle
Window.draw(rect);
}
}
I get a blank screen if I add that in. I wanted the rectangles to be transparent but I changed it to pink just in case that was the problem (Which it wasn't)
Screen scrolling code:
void Camera::Update(float x, float y)
{
cameraX = x - (ScreenWidth / 2);
cameraY = y - (ScreenHeight / 2);
if (cameraX < 0)
cameraX = 0.0;
if (cameraY < 0)
cameraY = 0.0;
CameraPosition.reset(sf::FloatRect(cameraX, cameraY, ScreenWidth, ScreenHeight));
CameraPosition.setViewport(sf::FloatRect(0,0,1,1));
}
For the first one: since you are scrolling by changing the sf::View, calculate the view offset and add it to your coordinates:
[...]
float x_offset = Window.getView().getCenter().x - Window.getSize().x * .5f;
float y_offset = Window.getView().getCenter().y - Window.getSize().y * .5f;
rect.setPosition(sf::Mouse::getPosition(Window).x/32 * 32 + x_offset,
sf::Mouse::getPosition(Window).y/32 * 32 + y_offset;
For the second one... uhhh I've got nothing right now. I've checked SFML and a sf::RectangleShape is default-initialized to have a size of (0, 0) so that's not the issue. Maybe the problem is in surrounding code?